当前位置: 首页 > news >正文

C++ 继承与派生入门:从基础到实践

引言

在面向对象编程中,继承是三大核心特性(封装、继承、多态)之一。它允许我们基于已有的类创建新的类,从而实现代码复用和层次化设计。

在我学习 C++ 的过程中,继承这个概念一开始让我感到抽象——什么是基类?什么是派生类?继承方式有什么区别?今天,我将通过简洁的示例,带你快速理解继承与派生的核心知识。

第一部分:继承的基本概念

一、什么是继承?

继承允许我们创建一个新类(派生类)来吸收另一个已存在类(基类)的成员。

// 基类(父类):被继承的类 class Person { // 成员... }; // 派生类(子类):继承基类的类 class Student : public Person { // 新增成员... };

二、为什么需要继承?

// 不使用继承:代码重复 class Person { int id; string name; public: void setId(int i) { id = i; } void setName(string n) { name = n; } void show() { cout << name << "(" << id << ")" << endl; } }; class Student { int id; string name; float score; // 学生特有的成绩 public: void setId(int i) { id = i; } void setName(string n) { name = n; } void setScore(float s) { score = s; } void show() { cout << name << "(" << id << "), score:" << score << endl; } }; // 问题:Person 和 Student 有大量重复代码!
// 使用继承:代码复用 class Person { int id; string name; public: Person(int i, string n) : id(i), name(n) {} void setId(int i) { id = i; } void setName(string n) { name = n; } void show() { cout << name << "(" << id << ")" << endl; } }; // Student 继承 Person,自动拥有 id、name 及相关方法 class Student : public Person { float score; public: Student(int i, string n, float s) : Person(i, n), score(s) {} void setScore(float s) { score = s; } void show() { Person::show(); // 调用基类的 show cout << "score: " << score << endl; } };

第二部分:三种继承方式

C++ 提供了三种继承方式:publicprotectedprivate。它们控制着基类成员在派生类中的访问权限。

一、继承方式总览

基类成员访问限定public 继承protected 继承private 继承
public 成员→ public→ protected→ private
protected 成员→ protected→ protected→ private
private 成员不可访问不可访问不可访问

二、图解继承方式

三、代码示例

class Person { private: int pid; string name; protected: void setPid(int id) { pid = id; } void setName(string n) { name = n; } public: Person(int id, string n) : pid(id), name(n) {} void eat() { cout << name << " is eating" << endl; } void sleep() { cout << name << " is sleeping" << endl; } void show() { cout << name << "(" << pid << ")" << endl; } }; // 1. public 继承(最常用) class StudentPublic : public Person { public: StudentPublic(int id, string n) : Person(id, n) {} void study() { // 可以访问 protected 成员 setPid(100); setName("张三"); // 可以访问 public 成员 eat(); sleep(); // ❌ 不能访问 private 成员 // pid = 100; // 错误! // name = "李四"; // 错误! } }; // 2. protected 继承 class StudentProtected : protected Person { public: StudentProtected(int id, string n) : Person(id, n) {} void study() { // 派生类内部:protected 成员仍可访问 setPid(100); setName("李四"); eat(); // 在派生类内部,public → protected,仍可访问 sleep(); } }; // 3. private 继承 class StudentPrivate : private Person { public: StudentPrivate(int id, string n) : Person(id, n) {} void study() { // 派生类内部:所有非 private 成员仍可访问 setPid(100); setName("王五"); eat(); sleep(); } }; int main() { // public 继承:对象可以访问 public 成员 StudentPublic sp(1, "张三"); sp.eat(); // ✅ 可以 sp.sleep(); // ✅ 可以 // sp.setPid(2); // ❌ 错误!protected 成员不可访问 // protected 继承:对象不能访问任何基类成员 StudentProtected sp2(2, "李四"); // sp2.eat(); // ❌ 错误!eat 变成了 protected // private 继承:对象不能访问任何基类成员 StudentPrivate sp3(3, "王五"); // sp3.eat(); // ❌ 错误!eat 变成了 private return 0; }

第三部分:派生类的构造函数

一、构造函数的调用顺序

重要规则:派生类的构造函数默认会调用基类的无参构造函数

class Person { private: int pid; string name; public: // 无参构造函数 Person() { cout << "Person 无参构造函数" << endl; pid = 0; name = ""; } // 有参构造函数 Person(int id, string n) : pid(id), name(n) { cout << "Person 有参构造函数" << endl; } }; class Student : public Person { private: float score; public: // 没有显式调用基类构造函数 → 默认调用 Person() Student(float s) : score(s) { cout << "Student 构造函数" << endl; } // 显式调用基类有参构造函数 Student(int id, string n, float s) : Person(id, n), score(s) { cout << "Student 有参构造函数" << endl; } }; int main() { cout << "=== 创建 s1 ===" << endl; Student s1(90); // 调用 Person() + Student(float) cout << "\n=== 创建 s2 ===" << endl; Student s2(1001, "张三", 95); // 调用 Person(int,string) + Student(...) return 0; } /* 输出: === 创建 s1 === Person 无参构造函数 Student 构造函数 === 创建 s2 === Person 有参构造函数 Student 有参构造函数 */

二、构造函数的调用顺序总结

第四部分:完整示例——Student 继承 Person

#include <iostream> #include <string> using namespace std; class Person { private: int pid; // 私有成员:派生类无法直接访问 string name; protected: // 受保护成员:派生类可以访问 void setPid(int id) { pid = id; } void setName(string n) { name = n; } public: Person(int id, string n) : pid(id), name(n) { cout << "Person 构造函数: " << name << endl; } void hi() { cout << "Hello, I'm " << name << " (ID: " << pid << ")" << endl; } ~Person() { cout << "Person 析构函数: " << name << endl; } }; class Student : public Person { private: float score; // 学生特有的成绩 public: // 在初始化列表上指定基类的构造函数 Student(int pid, string name, float score) : Person(pid, name) { // 调用基类构造函数 this->score = score; cout << "Student 构造函数: score=" << score << endl; } // 通过 protected 成员修改基类数据 void updatePidAndName(int pid, string name) { setPid(pid); // 调用基类的 protected 方法 setName(name); // 调用基类的 protected 方法 } // 重定义(隐藏)基类的 hi 函数 void hi() { Person::hi(); // 调用基类的 hi cout << "My score is " << score << endl; } ~Student() { cout << "Student 析构函数: score=" << score << endl; } }; int main() { cout << "=== 创建学生 s1 ===" << endl; Student s1(1001, "李刚", 900); cout << "\n=== 调用 hi() ===" << endl; s1.hi(); cout << "\n=== 修改信息 ===" << endl; s1.updatePidAndName(1003, "王刚"); cout << "\n=== 再次调用 hi() ===" << endl; s1.hi(); cout << "\n=== 程序结束 ===" << endl; return 0; } /* 输出: === 创建学生 s1 === Person 构造函数: 李刚 Student 构造函数: score=900 === 调用 hi() === Hello, I'm 李刚 (ID: 1001) My score is 900 === 修改信息 === === 再次调用 hi() === Hello, I'm 王刚 (ID: 1003) My score is 900 === 程序结束 === Student 析构函数: score=900 Person 析构函数: 王刚 */

第五部分:关键知识点总结

一、继承方式速查表

继承方式基类 public基类 protected基类 private派生类对象访问
publicpublicprotected不可访问✅ 可访问 public
protectedprotectedprotected不可访问❌ 不可访问
privateprivateprivate不可访问❌ 不可访问

二、派生类内部访问规则

class Base { private: int a; // 派生类不可访问 protected: int b; // 派生类可以访问 public: int c; // 派生类可以访问 }; class Derived : public Base { void func() { // a = 1; // ❌ 错误!不能访问 private b = 2; // ✅ 可以访问 protected c = 3; // ✅ 可以访问 public } };

三、构造函数调用规则

情况行为
派生类不写构造函数编译器生成默认构造函数,调用基类默认构造
派生类写了构造函数,未指定基类构造默认调用基类无参构造函数
基类没有无参构造函数派生类必须在初始化列表中显式调用基类有参构造

继承是 C++ 面向对象编程的核心特性之一。本文介绍了继承的基础知识:

  1. 三种继承方式:public(最常用)、protected、private

  2. 构造函数的调用顺序:先基类,后派生类

  3. 访问权限:派生类可以访问基类的 public 和 protected 成员

实用建议:

  • 日常开发中,99% 的情况使用 public 继承

  • protected 继承和 private 继承使用较少,主要在特殊场景(如实现组合关系)

  • 如果基类没有无参构造函数,派生类必须在初始化列表中显式调用基类构造函数

下一篇我们将深入讲解:

  • 继承中的构造函数与析构函数详解

  • 多重继承与菱形继承问题

  • 虚继承的解决方案

  • 运行时多态与虚函数

http://www.jsqmd.com/news/643785/

相关文章:

  • 有实力的预制直埋保温管厂家探讨,生产工艺成熟度深度剖析 - mypinpai
  • ncmdumpGUI完全指南:5分钟掌握网易云音乐NCM文件转换技巧
  • 番茄小说下载器终极指南:一键将在线小说转为EPUB电子书
  • 3分钟快速上手:智慧树自动刷课插件的完整使用指南
  • 财务主管警示:企业云支出浪费比例或高达30%
  • NBTExplorer:Minecraft玩家的终极NBT编辑器完全指南
  • 八股(四)JVM
  • Window Resizer完整指南:免费工具解决Windows窗口无法调整的难题
  • 2026年带压封堵施工公司哪家性价比高,这些品牌值得考虑 - myqiye
  • 3个实用技巧:如何用ncmdump轻松解密网易云音乐NCM文件
  • 5个高级配置技巧:如何深度优化NVIDIA Profile Inspector
  • 高效提升游戏性能:开源帧率优化工具完整指南
  • RAG系统必看!混合检索、关键词、语义一次讲清,生产级方案选型指南
  • ffmpeg的安装与配置
  • Joy-Con手柄修复指南:3个高效技巧彻底解决漂移和连接问题
  • 2026年3月优秀的波纹管源头厂家推荐,七孔梅花管/MPP电力管/PE硅芯管/雄安硅芯管,波纹管源头厂家推荐 - 品牌推荐师
  • 8分钟掌握网易云音乐NCM解密:免费工具让你的音乐随处播放
  • Qwen3-ASR-1.7B实操手册:如何导出SRT/VTT字幕文件用于Premiere剪辑
  • YOLOv8-pose实战:从零训练一个手部关键点检测模型(保姆级配置文件详解)
  • 共享出行平台:订单匹配与动态定价的策略
  • 多进程环境中解决PHP文件系统锁定问题的方法详解
  • HTML----列表与表格
  • 3步解锁网易云加密音乐:ncmdump实战解密指南
  • 如何高效使用智能清理工具:Windows Cleaner完整操作指南
  • DeepSeek V4迟迟未发布的核心原因
  • Wan2.2-I2V-A14B企业级应用:金融产品介绍短视频自动化生成流程
  • 终极指南:3步轻松解锁网易云音乐加密文件,让音乐随处播放
  • Arcmap实战:5分钟搞定CGCS2000到WGS84坐标转换(附详细截图)
  • 《整数唯一分解定理下递归素数生成体系的逻辑自洽性分析(完备性严格证明)》,其核心内容与逻辑结构总结
  • 魔兽争霸3兼容性增强插件:WarcraftHelper新手完全指南