深入理解 C++ 三大特性之一 继承

深入理解 C++ 三大特性之一 继承

欢迎来到干货小仓库!!!

今日的Commit 是明日的 Releasse,用持续交付的心态活成终身迭代的版本。


1.继承的定义

1.1定义格式

1.2继承关系和访问限定符

1.3继承基类成员访问方式的变化

类成员/继承方式public继承protected继承private继承
基类的public成员派生类的public成员派生类的protected成员派生类的private成员
基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员
基类的private成员在派生类中不可见在派生类中不可见在派生类中不可见
总结:

1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它

2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public>protected>private。4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强.

2.基类和派生类对象赋值转换

a. 派生类对象 可以 赋值给基类的对象/基类的指针/基类的引用。(向上转换/切割/切片,不会产生临时变量)

b. 基类对象 不能赋值给 派生类对象。(禁止 向下转换)

3.继承中的作用域

① 在继承体系中 基类派生类 都有独立的作用域。

②子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)

③ 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。

④ 注意在实际中在继承体系里面最好不要定义同名的成员

代码示例:

示例一:相同的成员变量,默认先访问派生类中的

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; // 学号 }; void Test() { Student s1; s1.Print(); };

示例二:相同的函数名,构成隐藏

// B中的fun和A中的fun不是构成重载,因为不是在同一作用域 // B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。 class A { public: void fun() { cout << "func()" << endl; } }; class B : public A { public: void fun(int i) { A::fun(); cout << "func(int i)->" <<i<<endl; } }; 

4.派生类的默认成员函数

a. 继承中 基类的成员声明 默认在派生类的成员声明的前面,初始化列表的顺序按声明顺序初始化.

b. 派生类的基类若没有默认构造,则需要在初始化列表中 对 基类进行 初始化.

c. 派生类中 会自动 基类的析构,把基类自己的资源进行释放。(不需要我们手动调用)

无需我们显示调用基类的析构----->编译器做了处理(子类析构函数完成时,自动调用基类的析构函数),由于交给我们手动释放会 无法保证先析构派生类,再析构基类。

为什么要先析构派生类 再析构基类?

由于 子类可能 使用到了 基类中的资源。

d. 编译器会统一把析构函数的函数名,进行特殊处理,处理成destructor(),由于后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同。

5.继承与友元

友元关系不能继承,也就是说基类的有源不能访问子类私有成员和保护成员。

示例:改代码编译不通过,出现语法错误

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; } int main() { Person p; Student s; Display(p, s); return 0; }

6.继承与静态成员

若基类定义了 static静态成员,则整个体系里面只有一个这样的成员。无论派生出多少个子类都只有一个 static成员示例。(相当于只是拥有使用权)

静态成员变量属于父类和派生类。

示例:

7.复杂的菱形继承及菱形虚拟继承

单继承:一个子类只有一个直接父类时称这个继承关系为单继承

多继承:一个子类有两个或两个以上直接父类时称这个继承关系为多继承。

菱形继承:是多继承的一种特殊情况。

导致 最后一个派生类有两份  class  Person 的数据,形成了 数据冗余和二义性。

解决方式:菱形虚拟继承,加上 virtual(继承公共基类的派生类上加)

7.1菱形虚拟继承底层原理

class A { public: int _a; }; class B : virtual public A { public: int _b; }; class C : virtual public A { public: int _c; }; class D : public B, public C { public: int _d; }; int main() { D d; d.B::_a = 1; d.C::_a = 2; d._b = 3; d._c = 4; d._d = 5; return 0; }

菱形虚拟继承的内存对象模型:

这里是通过了B和C的两个指针,指向的一张表。这两个指针叫虚基表指针,这两个表叫虚基表。虚基表中存的偏移量。通过偏移量可以找到下面的A

7.2习题

8.继承和组合的区别

9.继承的总结和反思


觉得不错的可以点赞+收藏咯!!!谢谢大家

Read more

【算法】二分查找(一)朴素二分

【算法】二分查找(一)朴素二分

目录 一、题目介绍 二、朴素二分 1.原理 二段性 时间复杂度(logn) 2.模板 四、提交代码 一、题目介绍 704. 二分查找 - 力扣(LeetCode) 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果 target 存在返回下标,否则返回 -1。 你必须编写一个具有 O(log n) 时间复杂度的算法。 示例 1: 输入: nums = [-1,0,3,

By Ne0inhk
【动态规划】子数组、子串问题

【动态规划】子数组、子串问题

* 一、[最大子数组和](https://leetcode.cn/problems/maximum-subarray/description/) * 二、[环形子数组的最大和](https://leetcode.cn/problems/maximum-sum-circular-subarray/description/) * 三、[乘积最大子数组](https://leetcode.cn/problems/maximum-product-subarray/description/) * 四、[乘积为正数的最长子数组长度](https://leetcode.cn/problems/maximum-length-of-subarray-with-positive-product/description/) * 五、[等差数列划分](https://leetcode.cn/problems/arithmetic-slices/description/) * 六、[最长湍流子数组](https://leetcode.cn/problems/longest-turbulent-sub

By Ne0inhk
Flutter 三方库 matrix 鸿蒙终端底层复杂超维数学算力适配突破:无缝植入极限级张量系统与密集线性代数矩阵运算推演算法,解锁端侧图形处理边界-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 matrix 鸿蒙终端底层复杂超维数学算力适配突破:无缝植入极限级张量系统与密集线性代数矩阵运算推演算法,解锁端侧图形处理边界-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 matrix 鸿蒙终端底层复杂超维数学算力适配突破:无缝植入极限级张量系统与密集线性代数矩阵运算推演算法,全面解锁端侧图形视觉处理边界并拔高数据分析算力上限 在图形学渲染、物理引擎模拟、复杂地理坐标转换以及端侧小型机器学习框架中,底层的矩阵运算(Matrix Operations)是决速步骤。matrix 库是一个专注于高性能线性代数计算的 Dart 库。本文将详解该库在 OpenHarmony 环境下的适配与实战应用。 封面 前言 什么是 matrix?它为 Dart 提供了一套类似于 NumPy 的多维数组运算接口。在鸿蒙操作系统这种强调极致流畅度和复杂视觉动效的系统中,利用高效的矩阵算法可以显著提升自定义 Canvas 绘图或实时传器数据处理的性能,避免因 Dart 层的低效循环导致的 UI 掉帧。 一、原理解析 1.1 基础概念 matrix 库核心基于

By Ne0inhk

优选算法——位运算

👇作者其它专栏 《数据结构与算法》《算法》《C++起始之路》 1.前要知识 《位操作符的妙用》 2.相关题解 2.1判定字符是否唯一 算法思路: 利用【位图】的思想,每一个【比特位】代表一个【字符】,一个int类型的变量的32位足够表示所有的小写字母。比特位里若为0,表示这个字符没有出现过;若为1,表示该字符出现过。 可以用一个【整数】来充当【哈希表】。 class Solution { public: bool isUnique(string astr) { //利用鸽巢原理优化 if(astr.size()>26) return false; int bitmap=0; for(auto i:

By Ne0inhk