https://guru.tistory.com/125?category=1038889
virtual 선언시 가상함수 테이블이 객체의 맨위, 즉 첫번째 메모리에 위치함.
: 만약 상속 관계에서의 형변환 발생시, 불가할 수 있음.
--> 이거를 도대체 왜한다고 생각할 수 있는데, 해야하는 상황이 발생해서 작성한 것임.
: vitual Function Table이라고 하고, 클래스의 가상 함수의 포인터들이 저장되는 포인터 배열이다.
vTable
부모클래스에 virtual이 선언되어 있는 멤버 함수가 있으면, 부모 클래스의 가상 함수 포인터들이 저장된 vTable이 생성되고, 자식클래스의 가상함수 포인터들이 저장된 vTable이 생성된다.
내부적으로는
부모 클래스 내부에는 부모 클래스의 vTable을 가리키는 포인터를 가지고 있고,
자식 클래스 내부에는 자식의 vTable을 가리키는 포인터를 가지고 있다.
호출하는 과정
실형식이 부모일 경우, 부모의 vTable을 가리키는 포인터가 부모의 vTable로 이동해 vTable에 있는 해당 함수를 호출하게 된다.
현재 내컴퓨터는 64비트이다.
64비트에서 포인터의 크기는 8바이트임.
: cat의 크기는 animal 클래스의 dAnimal 의 사이즈도 포함한 값이다.
virtual 키워드 사용
메모리 프로세스로 나타내면 이와 같다.
=> 가상함수 테이블의 크기가 8바이트인것이다.
virtual 함수마다 8바이트씩 증가하는 것이 아님!
-> virtual 키워드 사용으로 가상함수테이블을 가리키는 포인터가 각 클래스 마다
추가된 것이다.
이 때 Animal을 위한 가상함수 테이블, cat을 위한 가상함수 테이블로 나뉘어진다.
Animal의 가상함수 테이블에는 Animal 클래스 내부의 speak함수의 포인터를 가지고 있다.
cat의 가상함수 테이블에는 cat 클래스 내부의 speak함수의 포인터를 가지고 있다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
class Base
{
private :
int pri;
protected:
int pro;
public :
int pu;
void setPir(int n)
{
pri = n;
}
void setPro(int n)
{
pro = n;
}
};
class Derived : private Base
{
public :
void test()
{
//pu = 50;
//pri = 100;
//setPro(10);
}
};
class Derived2 : public Derived
{
public:
void test()
{
//pu = 50;
//pri = 100;
//setPro(10);
}
};
void recur(int n, int&cnt)
{
if (n == 0)
{
cnt++;
return;
}
if(n - 1 >= 0)
recur(n - 1, cnt);
if (n - 2 >= 0)
recur(n - 2, cnt);
}
class Animal
{
public :
virtual void speak()
{
cout << "Animal" << endl;
}
virtual ~Animal() = default;
double dAnimal;
};
class Cat : public Animal
{
public:
void speak() override
{
cout << "cat" << endl;
}
~Cat() = default;
double dCat;
};
int main(void)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
cout << sizeof(Animal) << endl;
cout << sizeof(Cat) << endl;
//Animal * polyAnimal = new Cat();
//polyAnimal->speak();
//delete polyAnimal;
return 0;
}