C++三大特性之----继承

继承:类的继承,就是新的类从已有类那里得到已有的特性。原有的类称为基类或父类,产生的新类称为派生类或子类。
在 c++ 中,一个派生类可以同时有多个基类,这种情况称为多重继承。如果派生类只有一个基类,称为单继承。派生类继承基类中除构造和析构函数以外的所有成员。
这里写图片描述
继承方式规定了如何访问基类继承的成员。继承方式有public, private, protected。如果不显示给出继承方式,默认为private继承。继承方式指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限。
公有继承
当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问。即基类的公有成员和保护成员被继承到派生类中仍作为派生类的公有成员和保护成员。派生类的其他成员可以直接访问它们。无论派生类的成员还是派生类的对象都无法访问基类的私有成员。
私有继承
当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。基类的公有成员和保护成员被继承后作为派生类的私有成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。通过多次私有继承后,对于基类的成员都会成为不可访问。因此私有继承比较少用。
保护继承
保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生类中,而基类的私有成员不可访问。派生类的其他成员可以直接访问从基类继承来的公有和保护成员,但是类外部通过派生类的对象无法访问它们,无论派生类的成员还是派生类的对象,都无法访问基类的私有成员。

派生类的构造函数
派生类中由基类继承而来的成员的初始化工作还是由基类的构造函数完成,派生类中新增的成员在派生类的构造函数中初始化。
1.如果基类中没有不带参数的构造函数,那么在派生类的构造函数中必须调用基类构造函数,以初始化基类成员。
2.派生类构造函数执行的次序:
(1)调用基类构造函数,调用顺序按照它们 被继承时声明的顺序 (从左到右);
(2)调用内嵌成员对象的构造函数,调用顺序按照它们在类中声明的顺序;
(3)派生类的构造函数体中的内容。

派生类的析构函数
派生类的析构函数的功能是在该对象消亡之前进行一些必要的清理工作,析构函数没有类型,也没有参数。析构函数的执行顺序与构造函数相反。
实例:

#include <iostream>
#include <time.h>
using namespace std;
// 基类 B1
class B1
{
public:
    B1(int i)
    {
        cout<<"constructing B1 "<<i<<endl;
    }
    ~B1()
    {
        cout<<"destructing B1"<<endl;
    }
};

//基类 B2
class B2
{
public:
    B2(int j)
    {
        cout<<"constructing B2 "<<j<<endl;
    }
     ~B2()
    {
        cout<<"destructing B2"<<endl;
    }
};

//基类 B3
class B3
{
public:
    B3()
    {
        cout<<"constructing B3"<<endl;
    }
    ~B3()
    {
        cout<<"destructing B3"<<endl;
    }
};

//派生类 C, 继承B2, B1,B3(声明顺序从左至右。 B2->B1->B3)
class C: public B2, public B1, public B3
{
public:
    C(int a, int b, int c, int d):B1(a), memberB2(d), memberB1(c),B2(b)
    {
        //B1,B2的构造函数有参数,B3的构造函数无参数
        //memberB2(d), memberB1(c)是派生类对自己的数据成员进行初始化的过程、
        //构造函数执行顺序, 基类(声明顺序)-> 内嵌成员对象的构造函数(声明顺序) -> 派生类构造函数中的内容
    }
private:
    B1 memberB1;
    B2 memberB2;
    B3 memberB3;
};

int main() 
{ 
    C obj(1,2,3,4);
    return 0; 
}
/* 输出结果 */
/*
constructing B2 2
constructing B1 1
constructing B3
constructing B1 3
constructing B2 4
constructing B3
destructing B3
destructing B2
destructing B1
destructing B3
destructing B1
destructing B2
*/

二义性问题
在单继承下,基类的public 和protected 成员可以直接被访问,就像它们是派生类的成员一样,对多继承这也是正确的。但是在多继承下,派生类可以从两个或者更多个基类中继承同名的成员。然而在这种情况下,直接访问是二义的,将导致编译时刻错误。
示例:

#include <iostream>
using namespace std;
class A
{
public:
void f();
};
class B
{
public:
void f();
void g();
};
class C : public A, public B
{
public:
void g();
void h();
};
int main(){
    C c1;
    // c1.f();    产生二义性问题,访问A中的 f()? or B的 f() ?
    //通过指定成员名,限定消除二义性
    c1.A::f();
    c1.B::f();
}

解决办法:
使用成员名限定法可以消除二义性,但是更好的解决办法是在类C中定义一个同名函数 f(), 类C中的 f() 再根据需要来决定调用A::f() or B::f(), 这样 c1.f() 将调用 C::f()
当一个派生类从多个基类派生类,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,也可能会出现二义性。
示例:

//  派生类 B1,B2 继承相同的基类 A, 派生类 C 继承 B1, B2
class A
{
public:
int a;
};
class B1 : public A
{
private:
int b1;
};
class B2 : public A
{
private:
int b2;
};
class C : public B1, public B2
{
public:
int f();
private:
int c;
};

int main(){
    C c1;
    c1.a();
    c1.A::a();
    c1.B1::a();
    c1.B2::a();
    return 0;
}

c1.a; c1.A::a; 这两个访问都有二义性,c1.B1::a; c1.B2::a;是正确的:
类C的成员函数 f() 用如下定义可以消除二义性:

int C::f()
{ 
    retrun B1::a + B2::a; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值