1.说明
C++允许多继承(区别于java,不能多继承,需要使用接口),但是C++的多继承也带来了 用户层面理解盲区(例如:内存布局等)
2.代码测试
实现一个基础的继承
class A{
public:
int a;
int b;
virtual void function1()
{
cout<<"this is class A ,function1 !"<<endl;
}
};
class B{
public:
int a;
int b;
virtual void function2()
{
cout<<"this is class B, function2 !"<<endl;
}
};
//class C extend A B
class C :public A, public B //1. 没有指明这个bulic 默认就是private继承
{
public:
int a;
int b;
virtual void function3()
{
cout<<"this is calss C, function3 !"<<endl;
}
//Class C里面新增加一个新的虚函数,这个函数和其他函数关系
virtual void function4()
{
cout<<"this is new virtual, before C obj is 40 !"<<endl;//这个虚函数的地址,是放到了A的虚函数表,还是B的虚函数表??
}
};
3.直接看结果
- 多继承C类,实例化后含有AB类中的成员变量(public的,注意private的也是占大小的)
- 注意访问继承的成员变量
- static成员变量在全局区!!
4.补充
在实际使用中,我们重新划分了几种模型
4.1 无虚函数的多继承
很好理解,没有虚函数表,子类对象中,直接位置先按顺序排父类对象,注意字节对齐,就可以。
4.2 有虚函数的多继承
在原来无虚函数的多继承上,也是按顺序排父类对象,对于含有虚函数的父类,第一个位置, 先是虚函数表。
4.3 虚基类多继承(虚继承)
多增加需要理解虚继承。 为什么需要虚继承? 当一个类要继承多个父类,而这个父类们,又继承于一个base基类,也就是菱形继承,这样导致了二义性,因此,引入 方法,在继承是增加virtual,进行虚继承,来保证,派生类对象中包含一个指向虚基类的指针,这个指针指向 一个虚基类表,虚基类表中存储了偏移量信息,用于在运行时确定基类成员的具体位置,这样保证,派生通过 多个路径继承同一个基类,也能保证基类成员的唯一访问。 本质上,就是基类只有一份,在里面,前面的内存模型和有虚函数的多继承类似,base基类只有一份,在子类对象 后面。
//虚基类,多继承
class grandfather{
public:
char *name; //8字节
virtual void grandfather_function(){
}
// 含有虚函数表8字节
};
class father_real : virtual public grandfather{
public:
char* name;
virtual void father1_function(){
}
};
class uncle: virtual public grandfather{
public:
char* name;
virtual void father2_function(){
}
};
class young_son : public father_real, public uncle{
public:
char* name;
};
其内存模型:
//----young son size
vptr //8字节 |father_real 指向father_real的虚基类表
char* name ; //8字节 | father_real
vptr //8字节 |uncle 指向uncle的虚基类表
char* name ; //8字节 |uncle
char* name ;//8字节 |young_son
vptr //8字节 |grandfather 指向grandfather的虚函数表
char* name ;//8字节 |grandfather
5.引申注意
对于字节对齐问题,因为受编译器影响,可以指定( attribute((packed)))对齐大小。
您还没有登录,请您登录后发表评论。