IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++】继承 -> 正文阅读

[C++知识库]【C++】继承

一、继承的概念

1. 继承的定义

保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类

image-20220416131815834


继承规则(私密程度:private > protected > public)

image-20220416155619652


2. 继承的赋值兼容

切割、切片:

  • 子类的值,地址,引用都可以赋值给父类

这里不是类型转换,而是语法支持,中间不会产生临时变量

  • 但父类不能给子类,父类的指针和引用可以给子类,但注意可能存在越界问题,因为子类把父类看作一个子类的

3. 继承的作用域

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

    当遇到同名变量时遵从就近原则(全局和局部变量的话,优先访问局部,想要访问全局加上::)

    在此假设上,如果子类和父类存在同名变量,当调用子类成员函数访问时,优先访问子类变量

    这种现象叫隐藏/重定义

  • 尽管继承了,如果想要访问父类成员必须指定作用域


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

  • 基类成员调用基类成员的默认成员函数
  • 子类的内置类型成员,调用自己的默认成员函数,自定义类型成员,调用自定义类型的成员函数

  • 父类没有默认成员函数,必须自己写

  • 如果存在浅拷贝和资源释放的问题,系统的默认成员函数不能支持,必须自己写

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class parent
{
public:
	parent(const char* name = "peter")
		: _name(name)
	{
		cout << "parent()" << endl;
	}

	parent(const parent& p)
		: _name(p._name)
	{
		cout << "parent(const parent& p)" << endl;
	}

	parent& operator=(const parent& p)
	{
		cout << "parent operator=(const parent& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~parent()
	{
		cout << "~parent()" << endl;
	}


protected:
	string _name;

};


class child :public parent
{
public:
	//构造函数
	child(const char* s = "hello", int num = 0)
		:parent(s),
		_num(num)
	{}

	//拷贝构造
	child(const child& s)
		:parent(s),
		_num(s._num)
	{}

	//赋值重载
	child& operator=(const child& s)
	{
		if (this != &s)
		{
			parent::operator=(s);
			_num = s._num;
		}
		return *this;
	}

	void print()
	{
		cout << _name << endl;
		cout << _num << endl;

	}
private:
	int _num;
};


int main()
{
	child b = {"ball", 20};
	child c;
	c = b;
	c.print();

	return 0;
}

image-20220417143313485

利用父类的构造函数完成子类的拷贝构造

原理:切片/切割(子类赋值给父类)

  • 关于析构函数

析构函数名字会被统一处理成destructor()
那么子类的析构函数跟父类的析构函数就构成隐藏

子类析构函数结束会自动调用父类析构函数

遵循先析构子类,再析构父类


5. 继承和友元

  • 友元关系不能继承

6. 继承和静态成员

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类(继承多少次),都只有一 个static成员实例


7. 菱形继承和菱形虚拟继承

  • **单继承:**一个子类只有一个直接父类

  • **多继承:**一个子类有两个或以上直接父类

  • **菱形继承:**A类,分别先单继承到2个子类B和C,再多继承到一个D类

此时存在问题:

  • 二义性,D类继承父类B和C中都有A类的成员,继承的是哪一个出现问题(当访问的时候不知道指的是谁的,需要指明作用域

    不使用virtual 但指明作用域

    指明作用域后会存分别不同的两份,先继承的放在前面,后继承在后面

    image-20220420162203138

  • 数据冗余,A类有个很大的数组,那D类要继承2份,会冗余


虚继承解决

在菱形的B、C类进行虚继承

class B : virtual public A
{};
class C : virtual public A
{};

此时再访问A成员不会出现二义性的报错(编译器优化成同一个)(在调试窗口会显示)


  • 不使用virtual,指明作用域

内存地址会显示不同

image-20220420162714490

image-20220420162744107

同一个地址的数值发生了变化


  • 当使用virtual,指明作用域时候

image-20220420163501980

这时候会发现,此时,B、C共同继承的A在最后面

image-20220420211353471

A为虚基类

D将其放在公共的地方,B、C可通过访问限定符去获取

如何获取?通过虚基表偏移量

image-20220420214530125

前面存储一个指针可以指向虚基表,而虚基表存储着虚基类的偏移量(存储在哪)

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:17:37  更:2022-04-22 18:20:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:15:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码