跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 继承机制详解:实现栈、同名隐藏与派生类默认成员函数

C++ 继承机制涉及访问权限控制、对象切片转换及作用域规则。通过公有继承可复用基类接口,但需注意私有成员不可见。利用模板类继承容器适配器可实现自定义栈结构,此时需显式指定命名空间避免编译错误。同名函数在不同作用域下构成隐藏而非重载,调用时需明确作用域。派生类构造顺序遵循先基类后派生类原则,析构则相反,且赋值运算符与拷贝构造函数需手动处理基类部分以避免数据丢失。

道系青年发布于 2026/3/22更新于 2026/9/1052 浏览
C++ 继承机制详解:实现栈、同名隐藏与派生类默认成员函数

C++ 继承机制详解

面向对象编程的三大特性中,封装我们已经熟悉,接下来深入探讨继承。继承允许我们复用代码并建立类之间的层次关系。本文将通过实际案例讲解继承的定义、访问控制、作用域规则以及派生类的默认成员函数行为。

继承的基本定义与访问权限

假设大学里有学生和教师,作为人都有姓名、住址和电话,但教师有职称,学生有学号。我们可以将共性封装在基类 Person 中,差异封装在子类 Student 和 Teacher 中。

class Person {
public:
    // 身份认证
    void identity() { 
        cout << "void identity()" << _name << endl; 
    }
protected:
    string _name = "张三";
    string _address;
    string _tel;
private:
    int _age = 18;
};

class Student : public Person {
public:
    void study() { /* ... */ }
protected:
    int _stuid;
};

访问权限规则

  1. 私有成员不可见:父类的 private 成员虽然被继承到了子类对象中(占用内存),但在语法上子类无法直接访问。这属于权限限制,而非未继承。
  2. 保护成员的作用:如果希望成员在类外不可见,但在子类中可见,应使用 protected。这是为继承场景专门设计的限定符。
  3. 总结:父类私有成员在子类中不可见。其他成员的访问权限取决于 Min(父类访问限定符,继承方式),即 public > protected > private。
  4. 默认继承方式:使用 class 关键字时默认为 private 继承;使用 struct 时默认为 public 继承。实践中通常使用 public 继承。

利用继承实现栈结构

之前我们用容器适配器实现了栈,这里尝试用继承的方式。当我们在派生类模板中使用基类模板的成员时,需要注意显式指定命名空间或类域。

如果在 push 函数中不指定类域,编译器可能找不到 push_back,因为模板需要按需实例化。例如:

#include <vector>
using namespace std;

namespace Keda {
template<class T>
class stack : public std::vector<T> {
public:
    void push(const T& x) {
        vector<T>::push_back(x); // 必须指定类域
    }
    void pop() {
        vector<T>::pop_back();
    }
    const T& top() {
        return vector<T>::back();
    }
    bool empty() {
        return vector<T>::empty();
    }
};
}

int main() {
    Keda::stack<int> st;
    st.push(1);
    st.push(2);
    while (!st.empty()) {
        cout << st.top() << " ";
        st.pop();
    }
    return 0;
}

通过宏替换容器类型(如 vector, list, deque)可以灵活实现不同底层的栈,预处理后宏会被替换为具体类型,不会存在残留的 CONTAINER。

对象赋值与切片

在公有继承条件下:

  1. 子类转父类:可以将子类对象的一部分'切割'出来赋值给父类对象,或者赋值给父类指针/引用。这被称为对象切片。
  2. 父类转子类:父类对象不能直接赋值给子类对象。
  3. 强制转换:父类指针指向子类对象时,可以通过强制类型转换安全地转为子类指针。

作用域与同名隐藏

当子类和父类中存在同名成员时,子类成员会屏蔽父类对同名成员的直接访问,这种现象称为隐藏。

class Person {
protected:
    string _name = "Keda";
    int _num = 111;
};

class Student : public Person {
public:
    void Print() {
        cout << _num << endl; // 打印 999
        // cout << Person::_num << endl; // 若要访问父类需指定作用域
    }
protected:
    int _num = 999;
};

重载 vs 隐藏

  • 函数重载:要求在同一作用域内,函数名相同但参数列表不同。
  • 函数隐藏:在不同作用域(如基类与派生类)中,只要函数名相同即构成隐藏,无论参数是否相同。

常见陷阱示例:

class A {
public:
    void fun() { cout << "func()" << endl; }
};

class B : public A {
public:
    void fun(int i) { cout << "func(int i)" << i << endl; }
};

int main() {
    B b;
    b.fun(10);      // 调用 B::fun(int),正常
    b.fun();        // 报错!A::fun 被隐藏
    b.A::fun();     // 正确调用基类版本
    return 0;
}

尽量避免定义同名成员,若必须定义,请明确指定作用域。

派生类的默认成员函数

派生类会自动生成四个默认成员函数,但它们的行为与基类密切相关。

1. 构造函数

子类构造函数必须初始化基类部分。如果基类没有默认构造函数,则必须在初始化列表中显式调用。

// 基类无默认构造函数的情况
Student(const char* name, int num) : Person(name), _num(num) {}

初始化顺序:先初始化基类成员,再初始化派生类成员。对象构造时,先调用基类构造函数,后调用派生类构造函数。

2. 拷贝构造函数

对于内置类型进行值拷贝,对于自定义类型调用其拷贝构造。基类部分同样调用基类的拷贝构造。

Student(const Student& s) : Person(s), _num(s._num) {}

3. 赋值运算符重载

子类的 operator= 会隐藏基类的 operator=。如果需要处理基类数据,必须显式调用基类作用域。

Student& operator=(const Student& s) {
    if (this != &s) {
        Person::operator=(s); // 显式调用基类赋值
        _num = s._num;
    }
    return *this;
}

4. 析构函数

子类析构函数不需要显式调用基类析构函数。系统规定:析构顺序是先派生类后基类。这样能保证子类成员先清理,基类成员后清理,符合资源释放逻辑。

核心要点总结

  1. 私有成员继承:私有成员确实被继承了(占用内存),但在子类中不可见,属于权限问题。
  2. 对象大小:子类对象不一定比父类大,若仅重写方法而未增加新成员,大小可能一致。
  3. 重载与隐藏:重载在同域,隐藏跨域。同名函数在派生类中会隐藏基类同名函数。
  4. 构造顺序:先基类后派生类。若基类无默认构造,子类必须显式调用。
  5. 析构顺序:先派生类后基类,无需手动调用基类析构。

理解这些机制有助于编写更安全、高效的 C++ 继承体系代码。

目录

  1. C++ 继承机制详解
  2. 继承的基本定义与访问权限
  3. 访问权限规则
  4. 利用继承实现栈结构
  5. 对象赋值与切片
  6. 作用域与同名隐藏
  7. 重载 vs 隐藏
  8. 派生类的默认成员函数
  9. 1. 构造函数
  10. 2. 拷贝构造函数
  11. 3. 赋值运算符重载
  12. 4. 析构函数
  13. 核心要点总结

更多推荐文章

查看全部
  • ComfyUI 快速部署指南:基于云原生环境的节点式 AI 绘图实践
  • myclaw:用 2000 行 Go 代码构建轻量 AI Agent Gateway
  • 字节华为网易等五家大厂 Android 开发面试经验与真题解析
  • 前端 pnpm workspace 详解
  • Higress 将 REST API 转换为 MCP Server 工具配置
  • OpenClaw.ai:Agentic AI 时代的 Spring Framework 时刻
  • Java 编译错误:源发行版 17 需要目标发行版 17
  • AI 生成前端 UI 的三步优化技巧
  • 基于 AI 工具快速生成计算机课题技术路线图
  • BoTorch 测试函数与基准评估:验证优化算法性能
  • GEO 生成式引擎优化:当 AI 成为流量入口,内容如何被看见
  • 汽车雷达多径环境下幽灵目标检测技术解析
  • 项目管理岗位:为何技能比学历更关键
  • 基于 OpenClaw 与 Claude 的自动化写作工作流搭建
  • AI 产品经理核心技能与自学路径指南
  • 利用 AI 快速掌握 XP.1024 新版本特性
  • 网络安全入门与职业发展学习路线指南
  • 基于 FastGPT 与 MCP 协议构建工具增强型智能体
  • 腾讯游戏 2026 Q1 财报:AI 技术驱动的新增长曲线
  • VR多相电源设计实战:架构、选型与Layout要点

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online