C++之类的继承与派生

一,继承与派生相关概念

  • 保持已有类的特性而构造新类的过程称为继承。
  • 在已有类的基础上新增自己的特性而产生新类的过程称为派生。
  • 被继承的已有类称为基类(或父类)
  • 派生出的新类称为派生类(或子类)

继承与派生问题举例:

二,继承与派生的目的

  • 继承的目的:实现代码重用、提高扩展性。
  • 派生的目的:当新的问题出现,原有程序无法解决(或不能完全解决)时,需要对原有程序进行改造。

派生类的声明

class 派生类名 : 继承方式 基类名

{

成员声明;

};

继承方式

不同继承方式的影响主要体现在:

  • 派生类成员对基类成员的访问权限
  • 通过派生类对象对基类成员的访问权限

三种继承方式:

  • 公有继承
  • 私有继承
  • 保护继承

三,公有继承(public)

类内部:

  • 基类的public和protected成员的访问属性在派生类中保持不变,但基类的private成员不可直接访问。
  • 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。

类外部:

  • 通过派生类的对象只能访问基类的public成员。

公有继承举例:

cpp 复制代码
#include <iostream>
using namespace std;

//父类
class A
{
public:
    void fun_A_public()
    {
        cout << "A::fun_A_public()" << endl;
    }

protected:
    void fun_A_protected()
    {
        cout << "A::fun_A_protected()" << endl;
    }

private:
    void fun_A_private()
    {
        cout << "A::fun_A_private()" << endl;
    }
};

//子类(public继承)
class B : public A
{
public:
    void fun_B_public()
    {
        cout << "B::fun_B_public()" << endl;
    }

protected:
    void fun_B_protected()
    {
        cout << "B::fun_B_protected()" << endl;
    }

private:
    void fun_B_private()
    {
        cout << "B::fun_B_private()" << endl;
    }

public:
    // 测试函数:在子类内部访问父类成员
    void test_in_class()
    {
        cout << "子类内部访问父类成员" << endl;
        fun_A_public();      //可访问(public)
        fun_A_protected();   //可访问(protected)
        // fun_A_private();  //无法访问(private)
    }
};

int main()
{
    B b;

    cout << "--- 子类对象访问父类成员 ---" << endl;
    b.fun_A_public();     //可访问(public)
    // b.fun_A_protected(); //无法访问(protected)
    // b.fun_A_private();   //无法访问(private)

    cout << "--- 子类对象访问子类成员 ---" << endl;
    b.fun_B_public();     //可访问
    // b.fun_B_protected(); //无法访问
    // b.fun_B_private();   //无法访问

    cout << endl;
    b.test_in_class();    // 测试在子类内部访问父类成员
    return 0;
}

运行结果:

程序详解:

四,保护继承(protected)

类内部:

  • 基类的public和protected成员都以protected身份出现在派生类中,但基类的private成员不可直接访问。
  • 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。

类外部:

  • 通过派生类的对象不能直接访问基类中的任何成员。

保护继承举例:

cpp 复制代码
#include <iostream>
using namespace std;

//父类
class A
{
public:
    void fun_A_public()
    {
        cout << "A::fun_A_public()" << endl;
    }

protected:
    void fun_A_protected()
    {
        cout << "A::fun_A_protected()" << endl;
    }

private:
    void fun_A_private()
    {
        cout << "A::fun_A_private()" << endl;
    }

public:
    // 测试:类A内部访问自身成员
    void test_in_A()
    {
        cout << "--- 类A内部访问自身成员 ---" << endl;
        fun_A_public();      //可访问
        fun_A_protected();   //可访问
        fun_A_private();     //可访问
    }
};

//子类(protected继承)
class B : protected A
{
public:
    void fun_B_public()
    {
        cout << "B::fun_B_public()" << endl;
    }

protected:
    void fun_B_protected()
    {
        cout << "B::fun_B_protected()" << endl;
    }

private:
    void fun_B_private()
    {
        cout << "B::fun_B_private()" << endl;
    }

public:
    // 测试:在子类内部访问父类成员
    void test_in_B()
    {
        cout << "--- 子类B内部访问父类A成员 ---" << endl;
        fun_A_public();      //可以访问(public 在 protected继承后变为 protected)
        fun_A_protected();   //可以访问(protected 保持为 protected)
        // fun_A_private();  //无法访问(private 无法继承)
    }
};

//外部测试
int main()
{
    A a;
    B b;

    cout << "--- 类A对象外部访问 ---" << endl;
    a.fun_A_public();        //可访问(public)
    // a.fun_A_protected();  //无法访问
    // a.fun_A_private();    //无法访问

    cout << endl;
    a.test_in_A();           //类A内部测试

    cout << endl;
    b.test_in_B();           //子类内部访问测试

    cout << endl;
    cout << "--- 类B对象外部访问 ---" << endl;
    // b.fun_A_public();     //无法访问(public 继承变为 protected)
    // b.fun_A_protected();  //无法访问(protected)
    b.fun_B_public();        //可以访问(B自己的public)
    // b.fun_B_protected();  //无法访问(protected)
    // b.fun_B_private();    //无法访问(private)

    return 0;
}

运行结果:

程序详解:

五,私有继承(private)

类内部:

  • 基类的public和protected成员都以private身份出现在派生类中,但基类的private成员不可直接访问。
  • 派生类中的成员函数可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员。

类外部:

  • 通过派生类的对象不能直接访问基类中的任何成员。

私有继承举例:

cpp 复制代码
#include <iostream>
using namespace std;

//父类
class A
{
public:
    void fun_A_public()
    {
        cout << "A::fun_A_public()" << endl;
    }

protected:
    void fun_A_protected()
    {
        cout << "A::fun_A_protected()" << endl;
    }

private:
    void fun_A_private()
    {
        cout << "A::fun_A_private()" << endl;
    }

public:
    // 测试:类A内部访问自身成员
    void test_in_A()
    {
        cout << "--- 类A内部访问自身成员 ---" << endl;
        fun_A_public();      //可访问
        fun_A_protected();   //可访问
        fun_A_private();     //可访问
    }
};

//子类(private继承)
class B : private A
{
public:
    void fun_B_public()
    {
        cout << "B::fun_B_public()" << endl;
    }

protected:
    void fun_B_protected()
    {
        cout << "B::fun_B_protected()" << endl;
    }

private:
    void fun_B_private()
    {
        cout << "B::fun_B_private()" << endl;
    }

public:
    // 测试:在子类内部访问父类成员
    void test_in_B()
    {
        cout << "--- 子类B内部访问父类A成员 ---" << endl;
        fun_A_public();      //可访问(但在B中变为private)
        fun_A_protected();   // 可访问(但在B中变为private)
        // fun_A_private();  //无法访问(private成员不可继承)
    }
};

//外部测试
int main()
{
    A a;
    B b;

    cout << "--- 类A对象外部访问 ---" << endl;
    a.fun_A_public();        //可访问(public)
    // a.fun_A_protected();  //无法访问
    // a.fun_A_private();    //无法访问

    cout << endl;
    a.test_in_A();           //类A内部测试

    cout << endl;
    b.test_in_B();           //子类内部访问测试

    cout << endl;
    cout << "--- 类B对象外部访问 ---" << endl;
    // b.fun_A_public();     //无法访问(在B中变为private)
    // b.fun_A_protected();  // 无法访问(在B中变为private)
    b.fun_B_public();        //可访问(B自己的public)
    // b.fun_B_protected();  //无法访问
    // b.fun_B_private();    //无法访问

    return 0;
}

运行结果:

程序详解:

六,继承访问总结

继承的本质是子类复用父类的代码。而继承方式 (public, protected, private) 则像一个"权限控制器",它决定了父类的成员(主要是 public 和 protected 成员)被子类继承后,在子类中拥有什么样的访问权限。

1、 两条基本原则

  1. 子类内部访问 :无论采用哪种继承方式,在子类的内部(其成员函数中),都可以直接访问父类的 public 和 protected 成员。这与继承方式无关,是继承的基本特性。

  2. 父类 private 成员的绝对性 :父类的 private 成员对于子类来说永远是不可见的,子类无法以任何方式直接访问。这一点不受继承方式的影响。

2、 三种继承方式的权限变化规则

继承方式决定了父类成员在子类中的最终访问权限 。这个最终权限取决于两个因素的最小值

  1. 成员在父类中的原始权限 (public > protected > private)。

  2. 继承方式的权限 (public > protected > private)。

权限取小原则:最终权限 = min(父类成员权限, 继承方式)

下面是具体的规则和总结表:

  • 规则 :父类的成员权限保持不变地继承下来。

    • 父类的 public 成员 -> 在子类中依然是 public。

    • 父类的 protected 成员 -> 在子类中依然是 protected。

  • 目的:实现 "is-a" 的关系,保持父类的公有接口在子类中仍然是公有的。

  • 规则 :将父类中更开放的 public 权限收缩为 protected。

    • 父类的 public 成员 -> 在子类中变为 protected。

    • 父类的 protected 成员 -> 在子类中依然是 protected。

  • 目的:不希望父类的公有接口被外界(类外部)直接访问,但希望在后续的继承链中可以被继续继承和访问。

  • 规则 :将父类的所有可访问成员全部收缩为 private。

    • 父类的 public 成员 -> 在子类中变为 private。

    • 父类的 protected 成员 -> 在子类中变为 private。

  • 目的:实现 "is-implemented-in-terms-of" 的关系,即子类仅仅是想复用父类的代码实现,而不希望父类的任何接口(无论是公有的还是保护的)对外暴露或被进一步继承。

3、 权限变化总结表

这张表清晰地展示了"权限取小"的规则:

|------------------|------------------|------------------|---------------|
| 继承方式 | 父类 public 成员 | 父类 protected 成员 | 父类 private 成员 |
| public 继承 | 在子类中变为 public | 在子类中变为 protected | 在子类中不可访问 |
| protected 继承 | 在子类中变为 protected | 在子类中变为 protected | 在子类中不可访问 |
| private 继承 | 在子类中变为 private | 在子类中变为 private | 在子类中不可访问 |

4、 类外部访问

  • 类外部(例如 main 函数)只能通过对象访问其 public 成员。

  • 因此,只有在**public继承**下,父类的public成员才能通过子类对象在类外部被访问。

  • 在 protected 和 private 继承下,父类的所有成员在子类中都变成了 protected 或 private,所以无法通过子类对象从外部访问

5、图示

相关推荐
冷徹 .3 小时前
2024ICPC区域赛香港站
数据结构·c++·算法
lly2024063 小时前
HTML 元素:构建网页的基础
开发语言
低调小一3 小时前
LRU缓存科普与实现(Kotlin 与 Swift)
开发语言·缓存·kotlin
爱好学习的青年人3 小时前
一文详解Go语言字符串
开发语言·后端·golang
沐怡旸3 小时前
【底层机制】std:: function 解决的痛点?是什么?如何实现?如何正确用?
c++·面试
浅川.253 小时前
xtuoj string
开发语言·c++·算法
望获linux3 小时前
【实时Linux实战系列】实时系统的可观测性:Prometheus 与 Grafana 集成
大数据·linux·服务器·开发语言·网络·操作系统
加油吧zkf4 小时前
Python入门:从零开始的完整学习指南
开发语言·前端·python
xqlily4 小时前
Kotlin:现代编程语言的革新者
android·开发语言·kotlin