C++ 继承与多态(三):虚基表与虚继承

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.虚函数:表中存放的是函数,用来实现泛型编程,运行时多态。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值