class A {
public:
void func1() {}
void func2() {}
public:
virtual void vfunc() {}
};
sizeof(A) = 4;//x86
sizeof(A) = 8;//linuxgcc
当一个或者多个虚函数加入到类中之后,编译器会向类中插入一个看不见的成员变量void *vptr
虚函数表指针(virtual table ptr),
当某个类中存在至少一个虚函数的时候,在编译期间编译器就会为类A生成一个虚函数表 vtbl
(virtual table),
虚函数表会一直伴随着类经过编译、链接、生成可执行文件、装载到内存中来,
对于有虚函数的类在编译期时,编译器向类的构造函数中安插为vptr赋值的语句,在创建类对象时使得vptr指向类的vtbl,
class A {
public:
void func1() {}
void func2() {};
public:
virtual void vfunc1() {}
virtual void vfunc2() {}
virtual ~A() {}
private:
int m_a;
int m_b;
};
sizeof(A) = 12;
类A在内存中的布局:
多态性:多态必须存在虚函数,没有虚函数绝不可能存在多态,并且只有调用虚函数时才有存在多态性的可能,
从代码上看多态的体现:
class Base {
public:
virtual void myvirfunc() {}
};
Base *ptr = new Base();
ptr->myvirfunc();//多态
Base base;
base.myvirfunc();//非多态
Base *pbase = &base;
pbase->myvirfunc();//多态
从表现形式上看多态的体现:
class Derive : public Base {
public:
virtual void myvirfunc();
};
//父类指针指向子类对象1
Derive derive;
Base *pbase1 = &derive;
pbase1->myvirfunc();
//父类指针指向子类对象2
Base *pbase2 = new Derive();
pbase2->myvirfunc();
//父类引用绑定子类对象
Derive derive2;
Base &refer_base = derive2;
refer_base.myvirfunc();
如果每个父类都有虚函数,那么每个父类都会有一个虚函数表,子类对象会包含每个父类的虚函数表指针,因此子类对象会有多个虚函数表指针,每个指针指向相应的虚函数表。
如果某个父类没有虚函数,那么子类对象就不会包含该父类的虚函数表指针,只会包含其他父类的虚函数表指针和成员变量。