C++三种继承

本文详细介绍了C++的三种继承方式:公有继承、私有继承和保护继承。公有继承体现了is-a关系,私有继承表示has-a关系,基类的public接口在派生类中变为private。保护继承则在继承链中允许访问所有基类接口。此外,还讨论了私有继承和保护继承的区别,以及如何通过using关键字改变成员的访问权限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++的三种继承方式

1.对比

特征公有继承保护继承私有继承
公有成员变成派生类共有成员派生类受保护成员派生类私有成员
受保护成员变成派生类受保护成员派生类受保护成员派生类私有成员
私有成员变成派生类只能通过基类接口访问派生类只能通过基类接口访问派生类只能通过基类接口访问
能否隐式向上转型是(只能在派生类中)

2.公有继承

表示了两个类有is-a的关系,我的另一篇博客介绍了公有继承,这里不再说明。

3.私有继承

表示了两个类有has-a的关系;对于私有继承,基类的public接口到了派生类变成了private,则,派生类不会对外提供基类的接口,这就是说私有继承是has-a关系的原因

I>.初始化

同样的,在调用派生类构造函数之前,要先调用基类构造,如果缺省成员初始化列表,调用基类的默认无参构造

class A {
    int a;
public:
    A(int a = 0) : a(a) { cout << "A::A()" << endl; }
};

class B : private A{
public:
    B(int a) : A(a){ 
        cout << "B::B()" << endl; 
    }
};

II>使用基类

i>基类成员

私有继承中,可以将基类当作是一个未命名的子对象成员,可以通过强制类型转换“给这个对象命名”

class B : private A{
private:
    A & obja = (A &)*this;
public:
    B(int a) : A(a){ 
        cout << "B::B()" << endl; 
    }
    void f() {
        obja.f();
    }
};

通过一个基类引用给基类命名,这样,就相当于是B中声明了一个a的子对象;对于obja来说,他是一个基类对象,他可以调用基类的接口

当然,对于公有继承,也可以这样做,但是共有继承对外提供基类接口,不是has-a的关系,这样做并没有意义。

ii>基类方法

第一种访问方式就是通过上面的给基类成员命名的方式。

接下来介绍第二种方式
对于基类的方法,在派生类中变为了private,所以,在类外,是无法访问的,但是在派生类中,仍然可以访问(类内可以访问自己的私有)。

class B : private A{
public:
    B(int a) : A(a){}

    void f(){
        A::f();//这里必须有域解析运算符,否则被认为是递归
    }
};

III>关于向上转型的问题——不能隐式的转型

可以显式地转换,这里必须强制类型转换,否则会报错

int main() {

    A *pa = (A*)new B(3);
    pa->f();
    return 0;
}

这里认真讨论一下

这里地B对象被当作一个A的实例化对象。因此,f()是否可以访问与f()在A中声明的访问权限有关 
f()为非虚函数

采用静态联编

f()为虚函数

采用动态联编,pa指向了B对象,所以会调用B::f();这里不关心B::f()的访问权限,因为在pa指针看来,只能通过虚函数表来调用函数,权限信息是A::f()的权限,所以,如果基类f()为公有,不论派生类f()的访问权限是什么,都可以访问。但是,如果用B的指针来指,就会有访问权限限制。

这里虽然必须用显式地方法向上转型,但是和公有继承有很多共通之处

4.保护继承

保护继承与私有继承一样,同样不为外部提供接口,同样可看作has-a关系

主要说一下保护继承和私有继承地区别

对于接口来说,私有继承无法访问间接基类的接口,而保护继承在继承链中,可以访问所有基类的接口。

私有继承将基类接口变为私有,则再次派生时,就会变得不可见。

最后强调一点

虽然说私有继承和保护继承建立了has-a的关系,但是不同于直接的子对象包含,继承仍然有继承的一些特性,比如说虚函数。

5.通过using重新定义访问权限

class B : private A{
public:
    using A::f;//相当于在B中声明了函数f,访问权限为public
};

使用using声明重新定义派生类可以访问的成员的访问权限。这 样,就相当于在B中相应的访问权限区域声明。

注意:派生类如果不可以访问,则不能修改权限,也就是说,不能修改派生类中的私有成员的访问权限。甚至可以将protected成员变成公有

class A {
protected:
    int a;
public:
    A(int a = 0) : a(a) {}
    void f() {
        cout << "A::f() ------ a = " << a << endl;
    }
};

class B : private A{
public:
    B(int a) : A(a){ 
        cout << "B::B()" << endl; 
    }
    using A::a; //派生类可以访问受保护,所以可以改变访问权限
    using A::f;
};

int main() {

    B obj(1);
    obj.f();
    cout << obj.a << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值