C++中虚继承时的构造函数示例详解

 更新时间:2023年09月06日 08:56:57   作者:向阳逐梦  
在虚继承中,虚基类是由最终的派生类初始化的,换句话说,最终派生类的构造函数必须要调用虚基类的构造函数,这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的,所以本文将通过代码示例给大家介绍一下C++虚继承构造函数

在虚继承中,虚基类是由最终的派生类初始化的,换句话说,最终派生类的构造函数必须要调用虚基类的构造函数。对最终的派生类来说,虚基类是间接基类,而不是直接基类。这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。

下面我们以菱形继承为例来演示构造函数的调用:

    #include <iostream>
    using namespace std;
    //虚基类A
    class A{
    public:
        A(int a);
    protected:
        int m_a;
    };
    A::A(int a): m_a(a){ }
    //直接派生类B
    class B: virtual public A{
    public:
        B(int a, int b);
    public:
        void display();
    protected:
        int m_b;
    };
    B::B(int a, int b): A(a), m_b(b){ }
    void B::display(){
        cout<<"m_a="<<m_a<<", m_b="<<m_b<<endl;
    }
    //直接派生类C
    class C: virtual public A{
    public:
        C(int a, int c);
    public:
        void display();
    protected:
        int m_c;
    };
    C::C(int a, int c): A(a), m_c(c){ }
    void C::display(){
        cout<<"m_a="<<m_a<<", m_c="<<m_c<<endl;
    }
    //间接派生类D
    class D: public B, public C{
    public:
        D(int a, int b, int c, int d);
    public:
        void display();
    private:
        int m_d;
    };
    D::D(int a, int b, int c, int d): A(a), B(90, b), C(100, c), m_d(d){ }
    void D::display(){
        cout<<"m_a="<<m_a<<", m_b="<<m_b<<", m_c="<<m_c<<", m_d="<<m_d<<endl;
    }
    int main(){
        B b(10, 20);
        b.display();
        C c(30, 40);
        c.display();
        D d(50, 60, 70, 80);
        d.display();
        return 0;
    }

运行结果:

m_a=10, m_b=20

m_a=30, m_c=40

m_a=50, m_b=60, m_c=70, m_d=80

请注意第 50 行代码,在最终派生类 D 的构造函数中,除了调用 B 和 C 的构造函数,还调用了 A 的构造函数,这说明 D 不但要负责初始化直接基类 B 和 C,还要负责初始化间接基类 A。

而在以往的普通继承中,派生类的构造函数只负责初始化它的直接基类,再由直接基类的构造函数初始化间接基类,用户尝试调用间接基类的构造函数将导致错误。现在采用了虚继承,虚基类 A 在最终派生类 D 中只保留了一份成员变量 m_a,如果由 B 和 C 初始化 m_a,那么 B 和 C 在调用 A 的构造函数时很有可能给出不同的实参,这个时候编译器就会犯迷糊,不知道使用哪个实参初始化 m_a。

为了避免出现这种矛盾的情况,C++ 干脆规定必须由最终的派生类 D 来初始化虚基类 A,直接派生类 B 和 C 对 A 的构造函数的调用是无效的。在第 50 行代码中,调用 B 的构造函数时试图将 m_a 初始化为 90,调用 C 的构造函数时试图将 m_a 初始化为 100,但是输出结果有力地证明了这些都是无效的,m_a 最终被初始化为 50,这正是在 D 中直接调用 A 的构造函数的结果。另外需要关注的是构造函数的执行顺序。

虚继承时构造函数的执行顺序与普通继承时不同:在最终派生类的构造函数调用列表中,不管各个构造函数出现的顺序如何,编译器总是先调用虚基类的构造函数,再按照出现的顺序调用其他的构造函数;而对于普通继承,就是按照构造函数出现的顺序依次调用的。修改本例中第 50 行代码,改变构造函数出现的顺序:

D::D(int a, int b, int c, int d): B(90, b), C(100, c), A(a), m_d(d){ }

虽然我们将 A() 放在了最后,但是编译器仍然会先调用 A(),然后再调用 B()、C(),因为 A() 是虚基类的构造函数,比其他构造函数优先级高。如果没有使用虚继承的话,那么编译器将按照出现的顺序依次调用 B()、C()、A()。

到此这篇关于C++中虚继承时的构造函数示例详解的文章就介绍到这了,更多相关C++虚继承构造函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 七夕表白! C语言实现爱情红玫瑰

    七夕表白! C语言实现爱情红玫瑰

    这篇文章主要为大家详细介绍了C语言实现爱情红玫瑰,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • C语言 pthread_create() 函数讲解

    C语言 pthread_create() 函数讲解

    这篇文章主要介绍了C语言 pthread_create() 函数讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • C语言使用函数实现字符串部分复制问题

    C语言使用函数实现字符串部分复制问题

    这篇文章主要介绍了C语言使用函数实现字符串部分复制问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C++ Array容器的显示和隐式实例化详细介绍

    C++ Array容器的显示和隐式实例化详细介绍

    这篇文章主要介绍了C++中Array容器的隐式实例化和显式实例化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-10-10
  • 剖析C++的面向对象编程思想

    剖析C++的面向对象编程思想

    这篇文章主要介绍了剖析C++的面向对象编程思想,C++的面向对象特性是其对C语言的重要拓展之处,需要的朋友可以参考下
    2015-09-09
  • C++实现假装蓝屏整蛊小程序

    C++实现假装蓝屏整蛊小程序

    因为工作的需要,有时候我们离开时并不想让别人看到我们电脑的内容,所以本文为大家分享了一个基于C++实现的假装蓝屏的小程序,需要的可以参考下
    2023-06-06
  • C/C++实现7bit与8bit编码互相转换

    C/C++实现7bit与8bit编码互相转换

    这篇文章主要为大家详细介绍了如何使用C/C++实现7bit与8bit编码互相转换功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-10-10
  • 深入理解C++ 字符变量取地址的特殊性与内存管理机制详解

    深入理解C++ 字符变量取地址的特殊性与内存管理机制详解

    在 C++ 编程中,字符变量的取地址行为和内存布局对程序行为有着深远的影响,尤其是在打印变量地址和访问内存内容时,本文将给大家介绍C++ 字符变量取地址的特殊性与内存管理机制,感兴趣的朋友一起看看吧
    2024-12-12
  • C语言选择排序算法及实例代码

    C语言选择排序算法及实例代码

    本篇文章主要介绍了 C语言选择排序算法,这里提供代码实例以便大家理解,通过本文,更好的理解排序算法
    2016-07-07
  • OpenCV实现低对比度图像脏污区域检测

    OpenCV实现低对比度图像脏污区域检测

    本文主要介绍了OpenCV实现低对比度图像脏污区域检测,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09

最新评论