C++ 继承

一、继承是什么?为什么要用继承?

继承是面向对象代码复用的核心手段。

  • 允许在保留原有类的基础上扩展功能,产生新类。
  • 原有类叫 基类/父类 ,新类叫 派生类/子类
  • 本质:类设计层面的复用,避免重复写相同成员。

没继承之前(代码冗余)

Student 和 Teacher 都有姓名、地址、电话、age、identity(),重复定义很麻烦。

用继承之后(代码复用)

把公共成员抽到 Person 基类,Student/Teacher 继承它,直接复用。

cpp 复制代码
class Person {
protected:
    string _name = "张三";
    string _address;
    string _tel;
    int _age = 18;
public:
    void identity() { cout << "认证:" << _name << endl; }
};

// 子类 : 继承方式 父类
class Student : public Person {
protected:
    int _stuid;
public:
    void study() {}
};

class Teacher : public Person {
protected:
    string _title;
public:
    void teaching() {}
};

二、继承的定义格式

cpp 复制代码
class 派生类 : 继承方式 基类
{
    // 新增成员
};

示例:

cpp 复制代码
class Student : public Person
{
public:
    int _stuid;
};

三、三种继承方式(最重要表格)

基类成员在派生类中的访问权限 = 取更小的那个
public > protected > private

基类成员 public 继承 protected 继承 private 继承
public public protected private
protected protected protected private
private 不可见 不可见 不可见

关键结论

  1. 基类 private 成员无论怎么继承,在子类都不可见
  2. 想让子类能访问、但类外不能访问 → 用 protected
  3. 实际开发 99% 用 public 继承
  4. class 默认 private 继承;struct 默认 public 继承。

四、基类 ↔ 派生类对象转换(切片/切割)

只有 public 继承才支持

1. 合法(可以)

  • 派生类对象 → 赋值给 基类对象
  • 派生类对象 → 赋值给 基类指针
  • 派生类对象 → 赋值给 基类引用

原理:把派生类中"属于基类的那部分"切过来用。

cpp 复制代码
Student s;
Person p = s;    // 可以
Person* pp = &s; // 可以
Person& rp = s;  // 可以

2. 不合法(不行)

  • 基类对象不能赋值给派生类对象
cpp 复制代码
Person p;
Student s = p; // 报错

五、继承中的作用域:隐藏(超级高频考点)

隐藏规则

  1. 基类和子类有独立作用域
  2. 子类和基类 同名成员 → 子类屏蔽基类 → 叫 隐藏
  3. 成员函数只要函数名相同就构成隐藏,不管参数!
  4. 想访问基类同名成员:基类::成员

示例:同名变量隐藏

cpp 复制代码
class Person {
protected:
    int _num = 111; // 身份证
};

class Student : public Person {
protected:
    int _num = 999; // 学号 → 隐藏父类
public:
    void Print() {
        cout << _num << endl;         // 子类 999
        cout << Person::_num << endl; // 父类 111
    }
};

示例:函数名相同即隐藏(不是重载)

cpp 复制代码
class A {
public:
    void func() { cout << "func()\n"; }
};

class B : public A {
public:
    void func(int i) { cout << "func(int)\n"; } // 隐藏 A::func()
};

// 调用
B b;
b.func(10);  // 走子类
// b.func(); // 报错!被隐藏了
b.A::func(); // 必须加类域才能调

六、派生类的 4 大默认成员函数(必考)

派生类的构造、拷贝构造、赋值、析构,必须配合基类

1. 构造函数

  • 子类构造 必须先调用基类构造
  • 基类无默认构造 → 子类必须在初始化列表显式调用
cpp 复制代码
Student(const char* name, int num) 
    : Person(name)  // 先初始化父类
    , _num(num)
{}

2. 拷贝构造

  • 子类拷贝构造 → 必须调用 基类拷贝构造
cpp 复制代码
Student(const Student& s)
    : Person(s)
    , _num(s._num)
{}

3. 赋值重载 operator=

  • 子类赋值会隐藏 父类赋值,必须显式调用
cpp 复制代码
Student& operator=(const Student& s) {
    if (this != &s) {
        Person::operator=(s); // 显式调用父类赋值
        _num = s._num;
    }
    return *this;
}

4. 析构函数

  • 子类析构 自动调用父类析构
  • 调用顺序:先析构子类 → 再析构父类
  • 构造顺序:先构造父类 → 再构造子类

4.2 如何实现一个 不能被继承的类

两种方法:

方法 1:C++98(构造函数私有)

  • 子类必须调用父类构造,私有后子类无法调用,无法实例化。
cpp 复制代码
class NonInherit {
private:
    NonInherit() {} // 私有构造
};

方法 2:C++11 final 关键字(最简单)

cpp 复制代码
class Base final {
    // 此类不能被继承
};

相关推荐
PHP实战开发录1 小时前
PHP脚本手动能跑定时任务却失败
开发语言·php·开发
蒸蒸yyyyzwd2 小时前
cpp 选手秋招学习笔记 day33
c++·笔记·求职招聘
郝学胜-神的一滴2 小时前
Effective Python 条款 10 :海象运算符_=
开发语言·python·程序人生·开源
wuyk5552 小时前
Python零基础入门第十四章:异常处理(try-except)
开发语言·python
wuyk5553 小时前
【Socket 进阶之路】第 3 章 TCP 三次握手 & 四次挥手深度剖析|连接建立、断开、状态机、TIME_WAIT 核心工程问题
服务器·开发语言·网络·物联网·网络协议·tcp/ip
彧azz8 小时前
图的存储结构详解:邻接矩阵的原理、实现与应用
开发语言·数据结构·学习·php
hansang_IR9 小时前
【题解】P4460 [CQOI2018] 解锁屏幕
c++·算法
嵌入式学习菌9 小时前
Modbus‑RTU 数据类型分析
开发语言·单片机·bug
ChampaignWolf9 小时前
在 SAP S/4HANA 内部基于 ICF Handler 从零实现 ABAP MCP Server:架构、代码与踩坑实录
c++·架构·sap·abap·mcp
matlab代码10 小时前
基于matlab数字图像处理的指纹识别系统【源码68期】
开发语言·matlab