C++ 继承与多态(三):虚基表与虚继承
一.菱形继承的二义性
首先利用菱形继承的案例(如下),说明如果派生类D中会出现两个_a,一个是B::_a, 还有一个是 C::_a, 这样便会有二义性,导致编译器报错。
#include <iostream>
using namespace std;
//菱形继承案例
class A {
public:
int _a;
};
class B :public A {
public:
int _b;
};
class C :public A {
public:
int _c;
};
class D :public B, public C{
public:
int _d;
public:
void display() {
//cout << "_a = " << _a << endl;//ERROR! 这里出现了菱形继承时不被允许的
cout << "B::_a = " << B::_a << endl; //可以!这里明确了是哪一个_a
cout << "C::_a = " << C::_a << endl; //可以!这里明确了是哪一个_a
cout << "_b = " << _b << endl;
cout << "_c = " << _c << endl;
cout << "_d = " << _d << endl;
}
};
void showSize() {
cout << "sizeof(A) = " << sizeof(A) << endl;
cout << "sizeof(B) = " << sizeof(B) << endl;
cout << "sizeof(C) = " << sizeof(C) << endl;
cout << "sizeof(D) = " << sizeof(D) << endl;
}
int main() {
D d;
d.display();
return 0;
}
1.(没有虚继承)内存布局:
使用虚继承:
#include <iostream>
using namespace std;
//菱形继承案例
class A {
public:
int _a;
};
class B :virtual public A {
public:
int _b;
};
class C :virtual public A {
public:
int _c;
};
class D :public B, public C{
public:
int _d;
public:
void display() {
//cout << "_a = " << _a << endl;//ERROR! 这里出现了菱形继承时不被允许的
cout << "B::_a = " << B::_a << endl; //可以!这里明确了是哪一个_a
cout << "C::_a = " << C::_a << endl; //可以!这里明确了是哪一个_a
cout << "_b = " << _b << endl;
cout << "_c = " << _c << endl;
cout << "_d = " << _d << endl;
}
};
int main() {
return 0;
}
2.有虚继承的内存布局:
这里说明一下内存布局,如B:0 ~ 4字节 存放{vbptr}, 4 ~ 8 字节 存放_b, 8 ~ 12 字节用来存放 _a, 那么B 一共占用12 字节, C也是同理。
再来说明D 的内存分布, 0 ~ 8 字节存放 B 的 {vbptr}和_b, 8 ~ 16 字节存放 C的 {vbptr}和_c,再存放一个 _a, _d
二.虚继承 与 虚函数 完全不相关的两个东西
这两者实际完全不相关:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <string>
using namespace std;
/*
虚继承与虚函数表:
注意,如果是进行了虚继承之后,就不再需要使用虚函数表了,如下面的程序(原因是虚基表中已经存放了虚基类,并不会出现二义性):
*/
class A{
public:
A(){
cout << "A()" << endl;
}
~A(){
cout << "~A()" << endl;
}
void print(){
cout << "this is A" << endl;
}
int a = 10;
};
class A1:virtual public A{
public:
A1(){
cout << "A1()" << endl;
}
~A1(){
cout << "~A1()" << endl;
}
void print(){
cout << "this is A1()" << endl;
}
int a = 1;
};
class A2:virtual public A{
public:
A2(){
cout << "A2()" << endl;
}
~A2(){
cout << "~A2()" << endl;
}
void print(){
cout << "this is A2()" << endl;
}
int a = 2;
};
class B:public A1, public A2{
public:
B(){
cout << "B()" << endl;
}
~B(){
cout << "~B()" << endl;
}
void display(){
cout << A::a << endl;
cout << A1::a << endl;
cout << A2::a << endl;
}
void print(){
cout << "this is B" << endl;
}
};
int main()
{
B *b = new B();
b->A1::print();
b->A2::print();
b->A::print();
//并没有实现多态(动态联编)
A *a = new B();
a->print();
delete b;
return 0;
}
三.总结
虚基表与虚函数表是两个完全不同的概念,也用来解决完全不同的问题:
1.虚基表:表中存放的是虚基类(如上面的class A),用来解决继承的二义性,是为了避免派生类中存储相同的成员。
2.虚函数:表中存放的是函数,用来实现泛型编程,运行时多态。