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 {
    // 此类不能被继承
};

相关推荐
ShineWinsu6 小时前
对于Redis:Hash类型的解析
c++·redis·分布式·缓存·面试·hash·哈希表
wuminyu6 小时前
JEP491中synchronized关键字引发的平台线程钉住解决方法简介
java·linux·c语言·jvm·c++
可乐鸡翅yeah_7 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
流形填表7 小时前
多校区题库标准化:Excel模板与校验脚本
开发语言·python
All for pursuit.7 小时前
【贪心-4】581.最短无序连续子数组
数据结构·c++·算法·leetcode
步行cgn7 小时前
AOP 通知的类型详解
开发语言
weixin_307779137 小时前
从“人操作仪器”到“Agent 自主发现”:OPL 金属材料自驱动实验室 MVP 技术论述
开发语言·人工智能·算法·架构
无名猿7 小时前
list 与 forward_list:链表真的比 vector 快吗
c++·性能优化·stl·内存管理·标准库
笑鸿的学习笔记7 小时前
C++笔记之SIMD与SSE指令集
开发语言·c++·笔记
汉克老师8 小时前
GESP2026年9月认证C++一级( 第二部分判断题(1~10题)精讲
c++·gesp·小学生·学c++编程