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++继承

什么是继承

继承(inheritance)是面向对象软件技术当中的一个概念,与多态封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

基类和派生类对象赋值转换(切片)

并且只能子类给父类,多的切掉一部分赋给少的,
当然也可以强行父类给子类,但是有很大风险

这个过程是天然的,也就是说这个过程是语法支持的行为,中途没有类型转换。而赋值时中间可能会有临时变量。

在这里插入图片描述

class Person
{
protected:
	string _name; // 姓名
	string _gender; // 性别
	int _age; // 年龄
};
class Student : public Person
{
public:
	int _No; // 学号
};

int main()
{
	Person p;
	Student s;
	p = s;

	return 0;
}

隐藏

区别于函数重载,隐藏是子类和父类中有同名成员(跟参数没关系),子类成员屏蔽父类对同名成员的直接访问,是不同作用域,而函数重载是必须要在同一作用域

最好就是不允许同名成员

派生类中的默认成员函数

类里面我们经常会用到的几个默认成员函数,构造,析构,拷贝构造,赋值

如果我们在派生类中不写会发生什么呢?

class Person
{
protected:
	string _name;
	string _gender;
	int _age;

	Person(const char* name = "Peter")
	{
		cout << "Person()" << endl;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
	
	Person(const Person& p)
	{
		cout << "Person(const Person& p)" << endl;
	}
};

class Student : public Person
{
public:
	int _stdid;
	string _s;
};

int main()
{
	Student s;
	return 0;
}

在这里插入图片描述
在这里插入图片描述

可以看到我们不写,父类还是调用了自己的构造和析构,子类则是自定义类型调用自己的默认构造函数,内置类型不处理,(子类的处理方式其实就和普通类一样)。
并且, 拷贝构造和赋值也是同理,父类的就调用父类的拷贝构造和赋值,子类的就和普通类一样,内置类型就浅拷贝,自定义类型调用自己的拷贝构造个赋值。

总结起来,其实规律很简单,即父类就调用父类的,子类则按普通类的处理规则处理


那什么情况我们必须自己写呢?

首先,如果父类没有默认构造,我们需要自己写。

class Student : public Person
{
public:
	Student(const char* name = "Peter", int stdid = 0)
		:Person(name) //注意这里的写法
		,_stdid(stdid)
	{}


	int _stdid = 0;
	string _s = "s";
};

如果我们还有空间需要释放,我们需要自己写析构。

	~Student()
	{
		Person::~Person();
	}

这里有个小知识,由于析构函数都会被统一处理成destructor()(这里又和多态有关系,到时候再填坑),因此构成隐藏了,所以这里要加域作用限定。

在这个析构这里,还有一个小问题:即我们实现子类的析构函数不需要显式调用父类析构函数。因为我们定义一个子类变量都是先定义父类,再定义子类,又由于栈里面的变量符合后进先出原则,我们析构时就会先析构子类再析构父类。子类析构函数结束时父类也会跟着析构,所以我们再自己实现一个就会析构两次。

还有就是浅拷贝问题,需要我们自己写拷贝构造和赋值解决。

	//s2(s1)
	Student(const Student& s)
		:Person(s)
		// 这里发生了切片,传子类给父类,自动切割,完成拷贝。
		, _stdid(s._stdid)
	{}
	Student& operator=(const Student& s)
	{
		if (&s != this)
		{
			Person::operator=(s);
			//这里记得加域作用限定符来限定,不然栈溢出
			_stdid = s._stdid;
		}
		return *this;
	}

继承与友元

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员 其实很好理解,父亲的朋友不一定是儿子的朋友,所以就不能继承。

菱形继承和菱形虚拟继承

这也许就是很多人说的C++的难点,其实多继承就是一个体现,多继承导致了菱形继承,随之而来就是菱形虚拟继承。因此,我们知道其复杂就不建议设计出菱形继承

什么是菱形继承?菱形继承的问题是什么?

单继承
在这里插入图片描述

多继承
在这里插入图片描述

菱形继承是多继承的一种特殊情况,即

在这里插入图片描述

菱形继承导致二义性和数据冗余。在Assistant对象中Person成员会存两份

在这里插入图片描述

class Person
{
public :
string _name ; // 姓名
};
class Student : public Person
{
protected :
int _stdid ; //学号
};
class Teacher : public Person
{
protected :
int _jobid ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
string _major ; // 主修课程
};
void Test ()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a;
a._name = "Peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,
// 但是数据冗余问题无法解决
a.Student::_name = "Jack";
a.Teacher::_name = "John";
}

在这里插入图片描述

解决,指定类域能解决二义性,但是解决不了数据冗余

如果像下面这样,Person类中成员很大。就容易浪费很多空间。

class Person
{
public:
	string _name; // 姓名
	int arr[1000];
};

在这里插入图片描述


这时候我们就可以使用虚拟继承virtual
class Teacher : virtual public Person
class Student : virtual public Person
用了之后就既没有二义性,也不会出现数据冗余。

当然最好的解决方法就是不要定义虚继承。

继承和组合

继承是一种is-a的关系,也就是说派生类都是一个基类对象
组合是一种has-a的关系,
就好像备胎轮胎的关系,我们说备胎轮胎,所以是继承。

还有链表的轮胎车子的关系,只能说车子轮胎,所以是组合。

两个都可以用的时候,优先使用组合

继承白盒复用,子类和基类之间的依赖性较强,耦合度高
组合黑盒复用,组合类之间没什么依赖关系,耦合度低

继承总结

这也许就是很多人说的C++的难点,其实多继承就是一个体现,多继承导致了菱形继承随之而来就是菱形虚拟继承。因此,我们知道其复杂就不建议设计出菱形继承前车之鉴,后车之师。所以后来的许多面向对象的语言都没有多继承,例如JAVA

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 00:51:43  更:2022-09-04 00:55:26 
 
开发: 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年5日历 -2024/5/19 7:50:24-

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