C++ 虚继承派生类构造函数的写法

Posted 小坏蛋_千千

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 虚继承派生类构造函数的写法相关的知识,希望对你有一定的参考价值。

昨天做题时候发现的问题

普通的继承中,我们可以在当前类(C)构造函数的初始化表中指明如何去构造直接父类(B),然后在该父类(B)构造函数的初始化表中指明如何构造祖先类(A)。


示例代码

class A

public:
    A() 
    A(int d):data(d) 
private:
    int data;
;

class B : public A

public:
    B() 
    B(int x):A(x) 
;

class C : public B

public:
    C() 
    C(int x):B(x) 
;


这样的写法是正确的,在创建一个 C 类型的实例时,程序会根据其构造函数的选择以及参数化表层层找到最上层的类,然后依次往下执行构造函数进行初始化。


但是在继承链中如果存在虚继承的话或许就不是这样了。

程序中有四个类: animal、aqu_animal、amp_animal、test

其中类之间的继承关系如下,除 test 以外其他继承都采用虚继承的方式。


示例代码

这里还是按照原来的思路进行初始化的工作

#include <iostream>
#include<stdio.h>
using namespace std;

class animal

protected:
    int height;
    int weight;
    char sex;
public:
    animal()
    
        cout<<"animal()"<<endl;
    
    animal(int h,int w,char s):
        height(h),weight(w),sex(s)
    
        cout<<"animal(int h,int w,char s)"<<endl;
    
;

class aqu_animal:virtual public animal

protected:
    int swimming_speed;
public:
    aqu_animal()
    
        cout<<"aqu_animal()"<<endl;
    
    aqu_animal(int h,int w,char s,int s_p):
        animal(h,w,s),swimming_speed(s_p)
    
        cout<<"aqu_animal(int h,int w,char s,int s_p)"<<endl;
    
;

class amp_animal:virtual public aqu_animal

public:
    amp_animal()
    
        cout<<"amp_animal()"<<endl;
    
    amp_animal(int h,int w,char s,int s_p,int r):aqu_animal(h,w,s,s_p),running_speed(r)
    
        cout<<"amp_animal(int h,int w,char s,int s_p,int r)"<<endl;
    
    void show()
    
        cout<<"height:"<<height<<endl;
        cout<<"weight:"<<weight<<endl;
        cout<<"sex:"<<sex<<endl;
        cout<<"swimming_speed:"<<swimming_speed<<endl;
        cout<<"running_speed:"<<running_speed<<endl;
    
private:
    int running_speed;
;

class test:public amp_animal

public:
    test() 
    test(int h,int w,char s,int s_p,int r):amp_animal(h,w,s,s_p,r)
    
        cout<<"test(int h,int w,char s,int s_p,int r)"<<endl;
        cout<<"----------------"<<endl;
        amp_animal::show();
    
;

int main()

    test t(50,20,'m',100,120);
    return 0;


执行结果

animal()
aqu_animal()
amp_animal(int h,int w,char s,int s_p,int r)
test(int h,int w,char s,int s_p,int r)
----------------
height:4309616
weight:7012244
sex:
swimming_speed:1978756045
running_speed:120

可以看到,除了 running_speed 正常外其他的变量都没有被正常赋值。


在函数的调用中,我们发现 test 类中的 test(int h,int w,char s,int s_p,int r) 正常执行了,并且它所附带的初始化表中的构造函数同样也被执行了( amp_animal(int h,int w,char s,int s_p,int r) )。

而在 amp_animal 类中利用 amp_animal(int h,int w,char s,int s_p,int r) 构造时的父类 aqu_animal 构造函数 aqu_animal(int h,int w,char s,int s_p) 并没有被执行,同样 animal 类中的 animal(int h,int w,char s) 也没有被执行,实际上都是调用了它们缺省的构造函数。


原因以及解决方法

C++ 中,如果继承链上存在虚继承的基类,则最底层的子类要负责完成该虚基类部分成员的构造。

即我们需要显式调用虚基类的构造函数来完成初始化,如果不显式调用,则编译器会调用虚基类的缺省构造函数,若虚基类中没有定义的缺省构造函数,则会编译错误。

因为如果不这样做,虚基类部分会在存在的多个继承链上被多次初始化。

很多时候,对于继承链上的中间类,我们也会在其构造函数中显式调用虚基类的构造函数,因为一旦有人要创建这些中间类的对象,我们要保证它们能够得到正确的初始化。


改法

#include <iostream>
#include<stdio.h>
using namespace std;

class animal

protected:
    int height;
    int weight;
    char sex;
public:
    animal()
    
        cout<<"animal()"<<endl;
    
    animal(int h,int w,char s):
        height(h),weight(w),sex(s)
    
        cout<<"animal(int h,int w,char s)"<<endl;
    
;

class aqu_animal:virtual public animal

protected:
    int swimming_speed;
public:
    aqu_animal()
    
        cout<<"aqu_animal()"<<endl;
    
    aqu_animal(int h,int w,char s,int s_p):
        animal(h,w,s),swimming_speed(s_p)
    
        cout<<"aqu_animal(int h,int w,char s,int s_p)"<<endl;
    
;

class amp_animal:virtual public aqu_animal

public:
    amp_animal()
    
        cout<<"amp_animal()"<<endl;
    
    amp_animal(int h,int w,char s,int s_p,int r):aqu_animal(h,w,s,s_p),running_speed(r),animal(h,w,s)
    
        cout<<"amp_animal(int h,int w,char s,int s_p,int r)"<<endl;
    
    void show()
    
        cout<<"height:"<<height<<endl;
        cout<<"weight:"<<weight<<endl;
        cout<<"sex:"<<sex<<endl;
        cout<<"swimming_speed:"<<swimming_speed<<endl;
        cout<<"running_speed:"<<running_speed<<endl;
    
private:
    int running_speed;
;

class test:public amp_animal

public:
    test() 
    test(int h,int w,char s,int s_p,int r):amp_animal(h,w,s,s_p,r),aqu_animal(h,w,s,s_p),animal(h,w,s)
    
        cout<<"test(int h,int w,char s,int s_p,int r)"<<endl;
        cout<<"----------------"<<endl;
        amp_animal::show();
    
;

int main()

    test t(50,20,'m',100,120);
    return 0;


注意 test 的构造函数初始化表中我们显式的调用了其间接父类的构造函数。


执行结果

animal(int h,int w,char s)
aqu_animal(int h,int w,char s,int s_p)
amp_animal(int h,int w,char s,int s_p,int r)
test(int h,int w,char s,int s_p,int r)
----------------
height:50
weight:20
sex:m
swimming_speed:100
running_speed:120

以上是关于C++ 虚继承派生类构造函数的写法的主要内容,如果未能解决你的问题,请参考以下文章

C++ ——虚继承时的构造函数

c++中,虚函数能不能被继承

C++ Primer 5th笔记(chap 18 大型程序工具)构造函数与虚继承

详解C++中基类与派生类的转换以及虚基类

c++继承总结

C++ Primer 5th笔记(chap 18 大型程序工具) 多重继承与虚继承