关于多重继承和虚拟继承

本文深入探讨了C++中的多重继承和虚拟继承概念,通过实例代码解释了多重继承的基本原理及其注意事项,着重阐述了虚拟继承的作用及与普通继承的区别。文中还提供了特殊初始化语义的理解案例,并附上了相关代码实现,帮助读者更直观地掌握C++继承机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两个概念在C++的书里面似乎也很少提及,所以看到这两个名词的时候我也往往自动忽略,今天有时间上网百度了一下,找到三篇写得不错的文章:

详解多重继承

关于C++中的虚拟继承的一些总结

详解C++虚拟继承

多重继承很好理解,后两篇是讲虚拟继承的,前一篇写的比较浅,看完基本能够理解这个概念,后一篇写的很详细,读起来不太好理解,自己动手写了代码在VC上跑了一下。

总的来说就是:

  1. 多重继承其实就是相当于合并了多个基类的成员(当然还有自身扩展的成员),与单继承的继承方式基本一致,要注意的是构造函数的调用顺序以及避免两个基类中成员(包括函数名)重名的情况发生,即使两个基类的成员函数有不同的参数类型也不行

  2. 虚拟继承是为了避免多重继承的两个以上基类来自同一个(二级)基类,因为这样一来多重继承的派生类就有了多套同样的基类成员,既浪费了内存,又产生多义性。所以引入虚拟的概念,类似于虚拟函数表一样,在虚拟继承的派生类中用一个指针指向同一个基类内存。

  3. 为什么不将全部的继承设为虚拟继承?因为虚拟继承会影响效率(间接引用基类),在非多重继承情况下占用了空间(引入指针)。

  4. 多重继承和虚拟继承一般不推荐使用。

难点:
  1. 第三篇文章中关于特殊的初始化语义这部分看得我有点乱,所以写了下面的代码:
    class base
    {
    public :
    	base(string name):base_name(name)
    	{
    		cout<<"in base"<<endl;
    	}
    	string base_name;
    };
    
    class A:virtual public base
    {
    public:
    	A(string A_name,string base_name):A_name(A_name),base(base_name)
    	{
    		cout<<"in A"<<endl;
    	}
    	string A_name;
    };
    
    class B:virtual public base
    {
    public:
    	B(string name, string name2):B_name(name),base(name2)
    	{
    		cout<<"in B"<<endl;
    	}
    	string B_name;
    };
    class C:public A, public B
    {
    public://对所有基类都初始化
    	C(string name1, string name2,string name3,string name4)
    		:base(name1),A(name2,name2),B(name3,name3),C_name(name4)
    	{
    		cout<<"in C"<<endl;
    	}
    	string C_name;
    };
    bool isNumber(char * str);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	C c("1","2","3","4");
    	cout<<c.base_name.c_str()<<","
    		<<c.A_name.c_str()<<","
    		<<c.B_name.c_str()<<","
    		<<c.C_name.c_str();
    
    }

输出结果是:

in base

in A

in B

in C

1, 2, 3, 4

说明base的构造函数只调用了一次,而且是在C类构造函数中被调用的,而A和B中的base()部分都失效了,所以其实传给A和B的构造函数中的name2是多余的,这也就是文章中说的写两个构造函数的原因。

class Bear : public virtual ZooAnimal {
public:
// 当作为最终派生类时
Bear( string name, bool onExhibit=true )
: ZooAnimal( name, onExhibit, "Bear" ),_dance( two_left_feet )
{}
// ... rest the same
protected:
// 当作为一个中间派生类时
Bear() : _dance( two_left_feet ) {}
// ... rest the same
};

2.第二篇文章中那道笔试题。

一开始没想明白,看了后面的评论才豁然开朗,主要是要记得虚拟继承情况下并非只有一个指针,还要给基类也开辟一段内存,所以比非虚拟继承的情况下多了一个指针。另外虚拟函数的表指针也不再与基类公用,需要另外多出一个虚拟函数表指针。

最后,如果你想继续挑战脑力,可以看这篇:《C++多继承和虚继承的内存布局

看完会对整体内存有更深的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值