多态—— 一个接口 多种形态,
编译器在执行过程中遇到virtual关键字的时候,将自动安装动态联编需要的机制,首先为这些包含virtual函数的类(注意不是类的实例)--即使是祖先类包含虚函数而本身没有--建立一张虚拟函数表VTABLE。在这些虚拟函数表中,编译器将依次按照函数声明次序放置类的特定虚函数的地址。同时在每个带有虚函数的类中放置一个称之为vpointer的指针,简称vptr,这个指针指向这个类的VTABLE。
一般来说一个对象的大小为所有成员变量的大小,但是当存在虚函数的时候即使这个类没有任何成员变量,他的对象的大小也不为0,为一个虚函数指针的大小。
当定义父类的一个函数为虚函数时,在子类中重载这个函数,用一个父类指针指向子类对象,并调用该函数的时候,调用的是子类的函数而不是父类的。如果
父类中这个函数不是虚函数的话,调用的就是父类的函数了
菱形继承
#include<iostream>
using namespace std;
class AA
{
public:
int _aa;
};
class BB : public AA
{
public:
int _bb;
};
class CC : public AA
{
public:
int _cc;
};
class DD :public BB, public CC
{
public:
int _dd;
};
int main()
{
DD d;
d.BB::_aa = 0;
d.CC::_aa = 1;
d._bb = 2;
d._cc = 3;
d._dd = 4;
cout<< sizeof(d) << endl;
return 0;
}
我们能够看到对象d中有继承的类BB和类CC,我们能够看到菱形继承中,对象d中存在两个成员_aa,这就存在问题,当我们想要访问_a时,编译器也不会知道我们想要访问的是哪一个变量,这就说明菱形继承存在一个“数据冗余”和“二义性“的问题。那么如何解决菱形继承所存在的这种问题呢
菱形虚拟继承
#include<iostream>
using namespace std;
class AA
{
public:
int _aa;
};
class BB :virtual public AA
{
public:
int _bb;
};
class CC :virtual public AA
{
public:
int _cc;
};
class DD :public BB, public CC
{
public:
int _dd;
};
int main()
{
DD d;
d.BB::_aa = 0;
d.CC::_aa = 1;
d._bb = 2;
d._cc = 3;
d._dd = 4;
cout<< sizeof(d) << endl;
return 0;
}
虚拟继承解决了这些问题