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、图示

相关推荐
打工仔折腾 AI7 分钟前
从零写一个CAD 05:以鼠标为中心的滚轮缩放,招法能复用但顺序不能反
开发语言·后端·python·性能优化·计算机外设·swift·ai agent 实战
CarIise10 分钟前
Java实训阶段查漏补缺复习笔记1
java·开发语言·笔记
事圆则缓11 分钟前
Kotlin 泛型方差实战:out、in、星投影与类型擦除
android·开发语言·kotlin
Code_Solitude27 分钟前
c语言:二分法的完整补充
c语言·开发语言·算法
智鸟科技GemeOpen开发者智能设备34 分钟前
MQTT智能通断器GSCW1M2P · 开发者实战指南
开发语言·物联网·智能家居
智者知已应修善业36 分钟前
【51单片机只有一个8*8点阵数据如何滚动起来一片595+一组IO+花样】2022-1-15
c++·经验分享·笔记·单片机·蓝桥杯·硬件架构
水饺编程1 小时前
第1章,[Win32 章节]:Windows 简史
c语言·c++·visual studio
青柠之夏cc1 小时前
前端拖拽功能原生实现,不引入拖拽库完成业务
开发语言·前端·python
ym hyd 1112 小时前
题库建立与考试系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·vue.js·spring boot·毕设
OKkankan2 小时前
Python 高阶语法(一):高阶函数、闭包、lambda 与 functools——从底层真正理解装饰器
开发语言·python