• 多继承原理抛砖


    虚继承

    如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。

    demo1

    #include <iostream>
    using namespace std;
    
    class B
    {
    public:
    	int b;
    protected:
    private:
    
    };
    
    class B1 : virtual public B
    {
    public:
    	int b1;
    
    };
    
    class B2 : virtual  public B
    {
    public:
    	int b2;
    };
    
    class C : public B1, public B2
    {
    public:
    	int c;
    };
    
    int main()
    {
    
    	C  c1;
    	c1.b1 = 100;
    	c1.b2 = 200;
    	c1.c = 300;
    
    	c1.b = 500; //继承的二义性 和 虚继承解决方案
    	//c1.B1::b = 500;
    	//c1.B2::b = 500;
    
    	return 0;
    }

    如果B1和B2继承B的时候不加virtual关键字,则main函数中 c1.b = 500; 运行的时候就会出错,因为b是B类中的数据成员,这样访问的时候会产生访问不明确,加上virtual之后B1和B2对B变成了虚继承,这样访问就不会出错。

    总结:

    总结:

    如果一个派生类从多个基类派生,而这些基类又有一个共同 的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。

    如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象。

    要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。

    虚继承声明使用关键字 virtual。

    注意增加virtual关键字后,构造函数调用的次数。

    demo2

    #include <iostream>
    using namespace std;
    
    
    class B
    {
    public:
    	B()
    	{
    		cout<<"B构造函数执行
    ";
    	}
    	int b;
    protected:
    private:
    
    };
    
    class B1 : virtual public B //12
    {
    public:
    	int b1;
    
    };
    
    class B2 :    public B //8
    {
    public:
    	int b2;
    };
    
    class C : public B1, public B2
    {
    public:
    	int c;
    };
    
    int main()
    {
    	cout<<sizeof(B)<<endl; //4
    	cout<<sizeof(B1)<<endl; //12 //加上virtual以后 , C++编译器会在给变量偷偷增加属性
    	cout<<sizeof(B2)<<endl;  //8
    	//cout<<sizeof(B)<<endl;
    
    <span style="white-space:pre">	</span>return 0;
    }
    
    

    如果给定义一个C,B的构造函数会调用两次,而如果给B1和B2加上virtual关键字,那么只会调用一次,说明虚继承的实现方式是多个子类拥有一个父类时,只生成一个父类。

    注意:另一种情况虚继承不能处理

    demo3

    class D1 
    {
    public:
    	int k;
    protected:
    private:
    };
    
    class D2 
    {
    public:
    	int k;
    protected:
    private:
    
    };
    
    class E :  public D1,  public D2
    {
    public:
    protected:
    private:
    };
    
    int main()
    {
    	E e1;
    	e1.D1::k = 100;
    	e1.D2::k = 200;
    
    	return 0;
    }

    如果两个父类D1和D2中有同名的数据成员,那么这里虚继承无法解决访问不明确的问题,只能通过域名作用符来进行区分。

    抛砖:demo2中测试了几个类的大小,当子类B2继承父类B时,B2的大小是8,很显然。但是B1虚继承B时,B1的大小是12,这里显然C++编译器处理虚继承的时候给变量偷偷添加了属性,具体情况我会在多继承的原理分析中详细阐述。





  • 相关阅读:
    设计模式—— 十 :模板方法模式
    设计模式—— 九 :抽象工厂模式
    StringUtils常用方法
    设计模式—— 八 :工厂方法模式
    Navicat查看并导出ER图
    设计模式—— 七 :单例模式
    设计模式—— 六:开闭原则
    设计模式—— 五:迪米特原则
    Java编码辅助工具:Mapstruct—— Java对象转换框架
    Java编码辅助工具:Lombok —— 避免重复臃肿的代码,提高效率
  • 原文地址:https://www.cnblogs.com/zhangyaoqi/p/4591569.html
Copyright © 2020-2023  润新知