C++基础学习-26继承的构造函数、多重继承、虚继承

继承的构造函数

  1. C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。
  2. 继承时,子类只能继承其直接基类(父类)的构造函数。默认(也即编译器自动给我们生成的)、拷贝、移动构造函数都是不能被继承的。那么怎么写继承的构造函数呢?
    格式:using 类名::类名(构造函数名);
class A {
public:
	A(int i,int j,int k){}

public:
    static int m_static;
};
int A::m_static = 100; //后续要使用的话必须初始化,不使用的话可以不用定义

class B : public A {
public:
    //B(int i,int j,int k):A(i,j,k) {};
    using A::A;//继承A的构造函数,会把基类都生成与之对应的派生类构造函数
    //B(int i,int j,int k):A(i,j,k) {};
    //如果有默认参数的话,会构造多个派生类构造函数
    //一个默认参数就会生成2个构造函数
    //A(int i,int j,int k=5){} ;
    //B(int i,int j,int k):A(i,j,k) {};
    //B(int i,int j):A(i,j) {};
};

int main () {
	B test(10,20,3);
	return 1;
}

  1. 如果子类中只含有使用using 类名::类名;继承过来的构造函数时,编译器不认为我们给该子类定义了构造函数的。因此编译器还会为我们自动生成子类的默认构造函数
  2. 如果基类的构造函数中带有默认的参数值,那么编译器一遇到using A::A;时,就会帮我们在子类中构造出多个构造函数来.

多重继承

class grand
{
public:
    grand(int v):m_valuegrad(v) {
        cout << "grand的构造函数" << endl;
    };
    ~grand() {
        cout << "grand的析构函数" << endl;
    }
    void initData() {
        cout << "grand initData" << endl;
    }
    void init() {
        cout << "grand init" << endl;
    }
    static int valuegrand;
    int m_valuegrad;
};

int grand::valuegrand = 100;

class A1 : public grand 
{
public:
    A1(int v):grand(v),m_valuea1(v)  {
        cout << "A1的构造函数" << endl;
    };
    ~A1() {
        cout << "A1的析构函数" << endl;
    }
    void initData() {
        cout << "A1 initData" << endl;
    }
    int m_valuea1;
};

class B1
{
public:
    B1(int v):m_valueb1(v) {
        cout << "B1的构造函数" << endl;
    };
    ~B1() {
        cout << "B1的析构函数" << endl;
    };
    void initData() {
        cout << "B1 initData" << endl;
    }
    int m_valueb1;
};

class C: public B1 ,public A1 
{
public:
    C(int v):B1(v),A1(v),m_valuec(v) {
        cout << "C的构造函数" << endl;
    };
    ~C() {
        cout << "C的析构函数" << endl;
    }
    int m_valuec;
};

1.多重继承的概念

一个子类继承自多个(2个及以上)父类。

2.静态成员变量

int grand::valuegrand = 100;
后续要使用的话必须初始化,不使用的话可以不用定义。
类跟类对应的对象都可以使用。

int main () {
	C c(1);
    c.init();//会调用基类grand
    c.A1::initData();//2个父类有同名函数需要标明具体类名
    c.B1::initData();
    c.valuegrand = 10000;
    A1::valuegrand = 1000;
    C::valuegrand = 1000;
    cout << c.valuegrand << endl;
	return 1;
}

3.派生类构造函数与析构函数

  1. 构造一个派生类对象将同时构造并初始化所有的直接基类的成分。
  2. 派生类的构造函数初始化列表只初始化它的直接基类,在多继承时也不例外。这样就会一层一层地把参数传递回最原始的基类,并把all的基类成分都构造好。
  3. 基类的构造顺序跟“派生列表”中基类的出现顺序是保持一致的!析构顺序则相反。
  4. 每个类的析构函数都只会进行自己这个类本身的成分的释放工作(类与类之间的析构函数是互不干扰的)。
    请添加图片描述

4.从多个父类继承构造函数

class A {
public:
    A(int tv) {}
};
class B {
public:
    B(int tv) {}
};
class C : public A,public B {
public:
    using A::A;//继承A类的构造函数 ==> C(int tv):A(tv){}
    using B::B;//错误!继承B类的构造函数是 ==> C(int tv):B(tv){}该构造函数和继承自A类的一模一样
};

上述code中C多继承自父类A和父类B的构造函数已经重定义了。因此我们只能自己定义一个属于子类C的构造函数,应该在C中添加:

C(int tv):A(tv),B(tv){
        cout << "C类的构造函数执行了!" << endl;
    }

类型转换

基类指针是可以指向一个派生类(子类)对象的:因为编译器会帮助我们隐式地执行这种派生类到基类的转换。究其原因:因为每个派生类对象都会包含基类对象的成分。在多继承中,基类指针也是可以指向一个派生类(子类)对象的!

    grand *g = new C(1);
    A1 *a = new C(1);
    B1 *b = new C(1);
    C tc(2);
    grand gg(tc);

这些写法都是正确的。

虚基类、虚继承(虚派生)

派生列表中,同一个基类只能出现一次,但是如下两种特殊情况例外:

  1. 派生类可以通过它的两个直接基类分别继承自同一个间接基类。
  2. 直接继承某个基类,然后通过另一个基类间接继承该类。
class grand
{
public:
    grand(int v):m_valuegrad(v) {
        cout << "grand的构造函数" << endl;
    };
    ~grand() {
        cout << "grand的析构函数" << endl;
    }
    void initData() {
        cout << "grand initData" << endl;
    }
    void init() {
        cout << "grand init" << endl;
    }
    static int valuegrand;
    int m_valuegrad;
};

int grand::valuegrand = 100;

class A1 : public grand 
{
public:
    A1(int v):grand(v),m_valuea1(v)  {
        cout << "A1的构造函数" << endl;
    };
    ~A1() {
        cout << "A1的析构函数" << endl;
    }
    void initData() {
        cout << "A1 initData" << endl;
    }
    int m_valuea1;
};

class A2 : public grand 
{
public:
    A2(int v):grand(v),m_valuea2(v)  {
        cout << "A2的构造函数" << endl;
    };
    ~A2() {
        cout << "A2的析构函数" << endl;
    }
    int m_valuea2;
};

class B1
{
public:
    B1(int v):m_valueb1(v) {
        cout << "B1的构造函数" << endl;
    };
    ~B1() {
        cout << "B1的析构函数" << endl;
    };
    void initData() {
        cout << "B1 initData" << endl;
    }
    int m_valueb1;
};

class C: public B1 ,public A1 ,public A2
{
public:
    C(int v):B1(v),A1(v)A2(v),m_valuec(v) {
        cout << "C的构造函数" << endl;
    };
    ~C() {
        cout << "C的析构函数" << endl;
    }
    int m_valuec;
};

int main() {
  	C ccc(1);
  	//ccc.m_valuegrad = 100;
	return 1;
}

运行结果为:
请添加图片描述
可以发现grand调用了2次构造2次析构函数。当调用共享基类的成员是会出现不明确错误。这就是多继承时对于基类成员变量的二义性问题
比如 ccc.m_valuegrad = 100; 提示C::m_valuegrad" 不明确。为了解决这样的错误同时为了提高效率,怎么才能调用一个呢?
只需在A1和A2继承grand的添加virtual。
class A1 :virtual public grand
class A2 :virtual public grand
同时把C(int v):B1(v),A1(v),A2(v),m_valuec(v)改为
C(int v):B1(v),A1(v),A2(v),gand(v),m_valuec(v)
修改之后再次运行结果为:请添加图片描述
OK,完美!

总结

  1. 若非必要,请一定不要选择用多继承的方式来编写你的代码!十分重要到建议:能用单继承解决问题,就不要用多继承!能不用virtual虚继承就尽量不用virtual继承来写代码!
  2. 若实在必要用到多继承时,提醒自己到底是否需要用虚继承的方式来进行多继承!(当产生成员变量的二义性问题时,就需要用虚继承来进行多继承!)。
  3. 学习多继承这个知识点不是说你一定要去常用它,而是为了让你去阅读别人的代码时不发懵!
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值