C# · 12月 20, 2021

C++虚继承和虚函数

虚继承

虚继承和普通继承有啥区别呢,上代码

class CA

{

int a;

}

class CB : public VA

{

int b;

}

class CD : public CA

{

int d;

}

class CE :public CB,public CD

{

int e;

}

cout<< sizeof(CB) << endl;//输出8

cout<< sizeof(CD) << endl;//输出8

cout<< sizeof(CE) << endl;//输出20

上面CE继承于CB和CD,而CD和CB都继承于CA,在CE中就会有两个CA,不但浪费了内存,还会出现二义性的问题

那么,虚继承可以解决这个问题

class CA

{

int a;

}

class CB: virtual public CA

{

int b;

}

class CD : virtual public CA

{

int d;

}

class CE :public CB,public CD

{

int e;

}

这里他们的字节是多少呢

cout<<sizeof(CB)<<endl;//输出12

cout<<sizeof(CD)<<endl;//输出12

cout<<sizeof(CE)<<endl;//输出24

欸,怎么内存反而增加了呢,别急

在类中,只要出现了 virtual 关键字,就会增加4字节,在CE继承与CD和CB的时候,CA只进行一次拷贝,所以让我们来数一下

CA:4字节

CB:CA+virtual+4字节=12

CD:CA+virtual+4字节=12

CE是如何进行构造的呢,我们看一下类的构造顺序

1丶虚基类

2丶基类

3丶子对象

4丶自身

构造顺序如下CA->CB->CD->CE

先进入CE,由CE进入CB,CB进入CA,构造CA->构造CB;

CB构造完成,进入CD,此时CA已经由CB构造完成,不再进行构造,只构造CD;CD构造完成,构造自身CE

所以CE的大小为:CA:4+CB:8+CD:8+自身的4=24

虚函数

class CA

{

int a;

public:

virtual void fun(){cout>>>”<<endl;}

virtual void fun(){cout>>>”<<endl;}

virtual void fun(){cout>>>>”<<endl;}

void afun();

}

虚函数在类中出现就会增加4字节,那么这个4字节是干什么用的呢

它是用来存储所有虚函数的首地址,我们叫它虚函数列表

我们可以用函数指针来访问到它

typedef void(*p)()

CA a;

p pfun;

for(int i=0;i<3;++i)

{

pfun=(p)*((int *)*(int *)(&a)+i);

pfun();

}

虚函数最大的作用是 实现多态的一个必需条件

派生类可以在类中重新定义与基类函数同名的函数,并且通过基类指针或引用访问到它

比如现在我们要做一个俄罗斯方块,方块有变形的行为,我们没必要给每一个方块都写一个变形的函数,这时可以通过虚函数来进行

class CA

{

public:

virtual void transf(){cout<<"CA变形"<<endl}

}

class CB : public CA

{

public:

void transf(){cout<<"CB变形"<<endl;

}

class CD :public CA

{

public:

void transf(){cout<<"CD 变形"<<endl;

}

void transf(CA & src)

{

src.transf();

}

CA a;

CB b;

Cd d;

transf(a);

transf(b);

transf(d);

//输出各自的变形函数

这里CA无论被继承多少次,都保持特性

class CE: public CD,public CB

{

void transf(){cout<<"CE变形"<<endl;

}

transf(CE);

//这里也是一样的输出自己的变形函数