【C++进阶】继承
目录​编辑本节学习目标1. 继承的概念及定义1.1 什么是继承1.2 继承定义语法基类成员在派生类的访问规则1.3 继承模板类模板父类2. 基类与派生类对象转换切片 / 切割 slicing3. 继承体系下作用域与隐藏name‑hiding同名成员变量隐藏示例同名成员函数隐藏重点选择题4. 派生类的默认 6 个成员函数派生类默认成员函数执行规则4.2 禁止类被继承两种写法5. 继承与友元6. 继承与静态成员7. 多继承、菱形继承与虚继承 virtual7.1 单继承、多继承7.2 菱形继承钻石继承—— 多继承特殊坑7.3 虚继承 virtual 解决菱形继承8. 继承与组合8.1 is‑a vs has‑a本篇核心考点总结本节学习目标理解继承的概念解决代码冗余复用问题分清父类 (基类)/ 子类 (派生类)掌握三种继承方式public / protected / private掌握基类成员在派生类中的访问规则理解派生类对象切片基类派生类指针引用转换继承体系作用域、成员隐藏name‑hiding区分隐藏和重载派生类 6 个默认成员函数构造、拷贝构造、赋值重载、析构的执行规则final 禁止继承继承与友元、继承与静态成员理解多继承、菱形继承带来二义性与数据冗余掌握虚继承virtual解决菱形问题分清is‑a继承 和has‑a组合理解白箱复用、黑箱复用开发优先组合1. 继承的概念及定义1.1 什么是继承继承是面向对象实现代码复用最重要机制。 在保留原有类基类 / 父类全部特性的基础之上扩展出新的类派生类 / 子类。场景学生 Student、老师 Teacher。两者都包含姓名、地址、电话、年龄、身份认证identity()学生独有学号、学习老师独有职称、授课。 不使用继承两份类中重复写相同成员代码大量冗余。把公共属性、方法抽出来放到Person父类Student、Teacher继承 Person直接复用父类成员只写自己独有的内容。#include iostream #include string using namespace std; //父类基类 class Person { public: void identity() { cout void identity() _name endl; } protected: string _name 张三; string _address; string _tel; int _age 18; }; //子类派生类 public继承Person class Student : public Person { public: void study() { } protected: int _stuid; //学号 }; class Teacher : public Person { public: void teaching() { } protected: string _title; //职称 }; int main() { Student s; Teacher t; s.identity(); //复用父类方法 t.identity(); return 0; }1.2 继承定义语法class 派生类名 : 继承方式 基类名 { //派生类自己新增的成员 };继承三种方式public、protected、private基类成员在派生类的访问规则基类的 private 私有成员无论哪种继承方式在派生类内部都不可见。注意不是没有继承到子类对象中只是语法禁止访问对象内存里面依然存在这份数据。 如果希望子类可以访问但是外部不能访问成员设置为protectedprotected 就是为继承场景诞生。简单口诀派生类中访问权限 min(基类成员权限继承方式)权限优先级public protected private表格基类成员public 继承protected 继承private 继承publicpublicprotectedprivateprotectedprotectedprotectedprivateprivate不可见不可见不可见语法细节使用class定义类默认继承方式是 private使用struct定义类默认继承方式是 public✅工程开发绝大多数场景只用public继承protected/private继承极少使用扩展性差。示例演示三种继承class Person { public: void Print() { cout _name endl; } protected: string _name; private: int _age; }; // class Student : protected Person; // class Student : private Person; class Student : public Person { protected: int _stunum; };1.3 继承模板类模板父类如果父类是类模板子类继承的时候必须带上基类模板域否则编译器找不到基类成员。 例stack 继承 vector模拟栈。namespace bit { templateclass T class stack : public std::vectorT { public: void push(const T x) { // 必须写 vectorT::push_back(x); // push_back(x); //直接写会编译报错模板按需实例化找不到名字 vectorT::push_back(x); } void pop() { vectorT::pop_back(); } const T top() { return vectorT::back(); } bool empty() { return vectorT::empty(); } }; } int main() { bit::stackint st; st.push(1); st.push(2); st.push(3); while(!st.empty()) { cout st.top() ; st.pop(); } return 0; }2. 基类与派生类对象转换切片 / 切割 slicing只针对public 公有继承派生类对象可以赋值给基类对象、基类指针、基类引用切片切割把派生类对象里面属于基类的那一部分切出来交给基类。派生类独有的成员直接被切掉丢弃。class Person { protected: string _name; string _sex; int _age; }; class Student : public Person { public: int _No; //学号 }; int main() { Student sobj; //1.派生类 → 基类指针 Person* pp sobj; //2.派生类 → 基类引用 Person rp sobj; //3.派生类赋值给基类对象发生对象切片调用基类拷贝构造 Person pobj sobj; // ❌基类对象不能直接赋值给派生类对象编译报错 // sobj pobj; return 0; }基类普通对象不能直接赋值给派生类对象。基类指针如果本来指向派生类对象可以强制转换为派生类指针安全转换后面多态章节学习dynamic_cast。3. 继承体系下作用域与隐藏name‑hiding基类、派生类拥有相互独立的作用域。成员隐藏遮蔽派生类和基类出现同名成员派生类成员会屏蔽基类同名成员。注意只要函数名字一样就构成隐藏参数不一样也隐藏不是重载重载只发生在同一个作用域如果需要在子类访问被隐藏的基类成员使用基类::成员名显式指定类域。工程编码建议尽量不要写同名成员可读性差容易踩坑。同名成员变量隐藏示例class Person { protected: string _name 小李子; int _num 111; //身份证号 }; class Student : public Person { public: void Print() { cout 姓名: _name endl; cout 身份证号: Person::_num endl; //显式指定基类域访问被隐藏成员 cout 学号: _num endl; } protected: int _num 999; //学号和父类_num同名发生隐藏 }; int main() { Student s1; s1.Print(); return 0; }同名成员函数隐藏重点选择题class A { public: void fun() { cout A::fun() endl; } }; class B : public A { public: //函数名字相同参数不同构成【隐藏】不是重载 void fun(int i) { cout B::fun(int i) i endl; } }; int main() { B b; b.fun(10); //调用B::fun(int) // b.fun(); //编译报错子类作用域把父类fun()隐藏了 b.A::fun(); //想要调用父类版本必须显式指定类域 return 0; }考点重载必须同一个类同一个作用域父子类之间同名函数不管参数是否一样都是隐藏。4. 派生类的默认 6 个成员函数编译器在满足条件时自动生成 6 个默认成员函数构造、拷贝构造、赋值运算符重载、析构、取地址两个重载。派生类默认成员函数执行规则派生类构造函数初始化列表阶段必须调用基类构造函数初始化继承过来的基类部分 如果基类没有无参默认构造派生类必须在初始化列表显式调用对应基类构造。对象构造顺序先基类构造再派生类构造。派生类拷贝构造必须调用基类拷贝构造完成基类部分拷贝。派生类 operator 赋值重载必须调用基类的赋值重载派生类会隐藏基类的 operator需要显式基类::operator(s)调用。派生类析构函数派生类析构执行完毕编译器自动调用基类析构对象析构顺序先派生类析构再基类析构和构造顺序相反。析构函数名字会被编译器特殊处理为destructor()基类和派生类析构函数名字不一样普通继承下构成隐藏不是重写多态章节 virtual 虚析构才会重写。完整示例代码#include iostream #include string using namespace std; class Person { public: Person(const char* name peter) :_name(name) { cout Person() endl; } Person(const Person p) :_name(p._name) { cout Person(const Person p) endl; } Person operator(const Person p) { cout Person operator(const Person p) endl; if(this ! p) { _name p._name; } return *this; } ~Person() { cout ~Person() endl; } protected: string _name; }; class Student : public Person { public: //派生类构造初始化列表调用基类构造 Student(const char* name, int num) : Person(name) , _num(num) { cout Student() endl; } //派生类拷贝构造调用基类拷贝构造 Student(const Student s) : Person(s) , _num(s._num) { cout Student(const Student s) endl; } Student operator(const Student s) { cout Student operator(const Student s) endl; if(this ! s) { //显式调用基类赋值重载派生类会隐藏基类operator Person::operator(s); _num s._num; } return *this; } ~Student() { cout ~Student() endl; //编译器自动在函数末尾调用 ~Person()不需要手写 } protected: int _num; }; int main() { Student s1(jack,18); Student s2(s1); Student s3(rose,17); s1 s3; return 0; }4.2 禁止类被继承两种写法C11final关键字修饰类该类不能被继承推荐class Base final { public: void func5() { cout Base::func5 endl; } protected: int a 1; }; // class Derive : public Base{}; //编译报错Base被final禁止继承C98 旧方式把基类构造函数设置为 private。派生类实例化对象必须调用基类构造基类构造私有子类无法访问子类不能实例化。5. 继承与友元❗友元关系不会继承。基类的友元函数不能直接访问派生类的 protected/private 成员。#include iostream #include string using namespace std; class Student; class Person { public: friend void Display(const Person p, const Student s); protected: string _name; }; class Student : public Person { protected: int _stuNum; }; void Display(const Person p, const Student s) { cout p._name endl; // cout s._stuNum endl; //编译报错友元不继承不能访问Student的_stuNum } int main() { Person p; Student s; // Display(p,s); //报错 return 0; }解决需要把 Display 也设置为 Student 的友元。6. 继承与静态成员基类里面的 static 静态成员整个继承体系之内只有唯一一份所有派生类对象共享同一份静态成员。 可以通过基类名、派生类名访问 public 静态成员。#include iostream #include string using namespace std; class Person { public: string _name; static int _count; }; int Person::_count 0; class Student : public Person { protected: int _stuNum; }; int main() { Person p; Student s; cout p._name endl; //普通成员每个对象独立一份地址不同 cout s._name endl; cout p._count endl; cout s._count endl; //静态成员地址完全相同共享同一份 cout Person::_count endl; cout Student::_count endl; return 0; }7. 多继承、菱形继承与虚继承 virtual7.1 单继承、多继承单继承一个派生类只有一个直接基类。多继承一个派生类拥有两个及以上直接基类。对象内存排布继承列表从左到右先继承的基类放在内存低地址后继承放后面派生类自己成员放最后。7.2 菱形继承钻石继承—— 多继承特殊坑继承关系Assistant助理同时继承Student和TeacherStudent、Teacher 都继承 Person。问题数据冗余Assistant 对象里面会存在两份 Person 基类数据一份来自 Student 路径一份来自 Teacher 路径二义性直接访问Assistant._name编译器不知道走哪一条继承路径编译报错。#include iostream #include string using namespace std; class Person { public: string _name; }; class Student : public Person { protected: int _num; //学号 }; class Teacher : public Person { protected: int _id; //职工编号 }; //助理多继承 Student、Teacher class Assistant : public Student, public Teacher { protected: string _majorCourse; }; int main() { Assistant a; // a._name peter; //编译报错二义性两份_name不知道选哪一个 //强制指定路径可以访问但是不能解决数据冗余 a.Student::_name xxx; a.Teacher::_name yyy; return 0; }7.3 虚继承 virtual 解决菱形继承在中间层继承的时候写virtual public Person虚继承公共父类 Person 在子类对象里面只保存唯一一份消除冗余和二义性。#include iostream #include string using namespace std; class Person { public: string _name; }; //虚继承 class Student : virtual public Person { protected: int _num; }; //虚继承 class Teacher : virtual public Person { protected: int _id; }; class Assistant : public Student, public Teacher { protected: string _majorCourse; }; int main() { Assistant a; a._name peter; //不再二义性只有唯一一份Person return 0; }⚠️注意虚继承会引入虚基表底层实现复杂有一定性能开销工程尽量不要设计菱形继承。Java 直接取消多继承从根源规避这个问题。扩展C 标准 IO 库ios_base就是典型虚继承菱形结构。8. 继承与组合8.1 is‑a vs has‑apublic 继承is‑a 是一个Student is‑a PersonBMW is‑a Car。 继承属于白箱复用基类内部细节对子类可见父子类耦合度很高基类改动会强烈影响子类。组合has‑a 拥有一个Car has‑a Tire汽车拥有轮胎。把别的类作为自己的成员变量。 组合属于黑箱复用只使用对方公开接口内部细节不可见耦合低维护性更好。✨开发经验优先使用组合只有满足 is‑a 语义再用继承实现多态必须使用继承。示例对比 stack 两种实现//方式1继承 vector is‑a不推荐 templateclass T class stack : public std::vectorT {}; //方式2组合 has‑a推荐容器适配器真实实现思路 templateclass T class stack { public: std::vectorT _v; };本篇核心考点总结继承实现类层次代码复用三种继承方式public/protected/private基类 private 成员子类永远不可见口诀min(成员权限,继承方式)。开发只用 public 继承。派生类对象切片派生类可以赋值给基类指针 / 引用 / 对象基类不能直接赋值给派生类。父子类同名成员构成隐藏 name‑hiding不是重载重载仅限同一个作用域基类::成员访问被隐藏成员。默认成员函数构造先基类后派生类析构先派生类后基类拷贝构造、赋值重载要处理基类部分。final 修饰类禁止继承。友元不能继承static 静态成员继承体系共享同一份。多继承会带来菱形继承两份公共基类数据冗余 访问二义性virtual虚继承解决尽量避免菱形继承。is‑a 用继承has‑a 优先用组合组合耦合低优先组合。面试简答Q基类 private 成员子类能不能继承能不能访问A内存上继承到子类对象但是语法不可访问子类需要访问就设置为 protected。Q成员隐藏和重载区别A重载在同一个作用域函数名相同参数不同父子不同作用域只要名字相同就是隐藏和参数无关。Q菱形继承问题怎么解决A中间层使用 virtual 虚继承最好设计上避免菱形继承。Q继承和组合怎么选Ais‑a 是继承has‑a 优先组合组合耦合更低。

相关新闻

后端技术栈怎么选?这5个维度帮你理清思路

后端技术栈怎么选?这5个维度帮你理清思路

后端技术栈选型是每个团队都会面临的难题。Java、Go、Python、Node.js、Rust……每种语言背后又有一堆框架和中间件。选对了,团队事半功倍;选错了,可能陷入“重构无尽头”的泥潭。其实,技术选型没有标准答案,但有一套可…

2026/9/24 18:00:50 阅读更多 →
python入门学习(二)

python入门学习(二)

# python中的循环语句 from operator import truedivfrom ctypes.macholib.dyld import DEFAULT_LIBRARY_FALLBACK from logging import error# if条件判断语句 --- 单分支 # if的核心在于布尔值 (True/False) 计算机非常死板,它必须得到一个…

2026/9/24 18:00:50 阅读更多 →
复杂工艺铝单板厂家推荐——从项目选型看行业头部企业

复杂工艺铝单板厂家推荐——从项目选型看行业头部企业

复杂工艺铝单板选型,本质上是在选一家能同时搞定双曲、冲孔、仿石材等多种工艺的系统供应商。巨星铭创年产500万方、年产值13亿元(2025年),在异形、圆弧、蜂窝等复杂版型铝单板领域积累了多个标志性项目——杭州大会展中心项目体量…

2026/9/24 18:00:50 阅读更多 →

最新新闻

ST-GCN骨骼动作识别项目实战:图卷积网络原理与工程实现详解

ST-GCN骨骼动作识别项目实战:图卷积网络原理与工程实现详解

简介:一套基于时空图卷积网络ST-GCN的骨骼动作识别Python毕业设计,涵盖源代码、训练好的模型与全套项目文档,面向计算机视觉、深度学习方向的毕设选题与课程作业。项目来自课程设计,代码均测试通过,实现了从骨骼关键点…

2026/9/24 22:45:40 阅读更多 →
Java工程师转型Agent开发的实战路径

Java工程师转型Agent开发的实战路径

1. 为什么Java工程师转Agent开发不是“换赛道”,而是“升级武器库”我带过三届校招Java后端团队,也参与过五个AI原生应用的从0到1落地。去年底有个典型场景:一位在支付系统写了七年Spring Boot的老同事,突然开始研究LangChain4j的…

2026/9/24 22:45:40 阅读更多 →
如何去除AI味?从95%到0%的AIGC降重改写指南

如何去除AI味?从95%到0%的AIGC降重改写指南

先把一个真实场景摆出来:你在某个AI对话框里让它写一篇产品推广文案,复制粘贴进在线AIGC检测工具,屏幕上跳出一行刺眼的数字——疑似AI生成比例95%。再把同一段文字发给一个做编辑的朋友看,对方扫了两眼就摇头:“这味儿…

2026/9/24 22:45:40 阅读更多 →
DeepSeek Harness Desktop:基于Electron的本地大模型评测工具

DeepSeek Harness Desktop:基于Electron的本地大模型评测工具

1. 项目概述:这不是一个“突然出现”的桌面应用,而是一次有迹可循的技术演进最近在 GitHub 上刷到 DeepSeek 官方仓库时,我下意识点开 Releases 页面,结果一眼就看到了deepseek-harness-desktop这个新包——不是 PR、不是草稿、不…

2026/9/24 22:45:40 阅读更多 →
从94%到0%:用Skill彻底去除AI写作痕迹的实操指南

从94%到0%:用Skill彻底去除AI写作痕迹的实操指南

1. 先认清"AI味"是什么:不是玄学,是统计学特征我拿自己前两天的一篇文章来开头。文章是让AI帮忙起草的,内容讲一个效率工具的使用心得。我自认为已经加了不少人情味的表述,结果发给一个朋友,他三秒就回了三个…

2026/9/24 22:45:40 阅读更多 →
Java数据类型与运算符避坑指南:从基本类型到Integer缓存

Java数据类型与运算符避坑指南:从基本类型到Integer缓存

最近带了个新人,他问我:Java 里到底有几种数据类型?我说 8 种基本类型。他又问:那 String 呢?我说 String 是引用类型。他接着问:那为什么有人总说 Java 的运算符优先级比数据类型还难记?遇到长…

2026/9/24 22:44:39 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →