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

C++系列-继承补充

🌈个人主页:羽晨同学 

💫个人格言:“成为自己未来的主人~”  

继承和友元

友元关系不能继承,父亲的朋友不能是你的朋友

比如在这个例子当中:

class Student;
class Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name;//姓名
};
class Student :public Person
{
public:
	//friend void Display(const Person& p, const Student& s);
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;
}

这个访问p._name是没有问题的,但是访问s._stuNum是会发生报错的,因为友元函数不能被继承,所以基类也就不能访问子类的私有和保护的成员。

那怎么样才能解决这个问题呢?

答案其实很简单,那就是:让孩子自己和朋友培养关系,也就是说,在派生类中再次写一次友元函数的声明。

class Student;
class Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name;//姓名
};
class Student :public Person
{
public:
	friend void Display(const Person& p, const Student& s);
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;
}

这样子,就不会发生报错了。

继承和静态成员

基类定义的静态成员,那么不管是基类还是派生类都只有这样一个静态成员,也就是说,静态成员是不会继承的。具体我们来看下面的代码:

class Person
{
public:
	Person()
	{
		++_count;
	}
protected:
	string _name;
public:
	static int _count;
};
int Person::_count = 0;
class Student :public Person
{
protected:
	int _stuNum;
};
int main()
{
	Person p;
	Student s;
	cout << &Person::_count << endl;
	cout << &Student::_count << endl;
	return 0;
}

我们可以看到的是,不管是基类的_count还是派生类的_count,它们的地址是相同的。所以,我们可以得到的是,静态成员修饰的变量或者函数是不会参与继承的。

菱形继承和菱形虚拟继承

单继承

一个子类只有一个父类,叫做单继承。

多继承

一个子类有多个父类,这是多继承

菱形继承

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

 

菱形继承的问题:数据冗余和二义性。怎么说呢,其实看上面的图,我们可以看到,Person的信息其实被Student和Teacher继承了一次,说明在Student和Teacher中都有Person的信息,当Assistant继承Student和Teacher的时候,继承了两次Person的信息,这就造成了数据的冗余和二义性。

 数据冗余和二义性

你看,在下面代码中同时存在数据冗余和二义性的问题:

class Person
{
public:
	string _name;
	int _id;
	int _tel;
	int _adress;
};
class Student :  public Person
{
protected:
	int _num;
};
class Teacher :  public Person
{
protected:
	int _id;
};
class Assistant :public Student, public Teacher
{
protected:
	string _majorCourse;
};
int main()
{
	Assistant a;
	a._name = "peter";

	return 0;
}

当我们运行这个代码的时候,是会报错的,原因是因为并不知道_name具体指向的是什么,其实这个很好解决,我们只要在前面加上特定类域的声明就可以了.比如:

int main()
{
	Assistant a;
	a.Teacher::_name = "peter";
	a.Student::_name = "jijiao";
	return 0;
}

但是这样子的话,其实数据冗余的问题是没有办法解决的,那我们应该怎么处理呢,这个时候就需要用到虚拟继承了。

虚拟继承是可以解决二义性和数据冗余的问题的,我们只要在第一次继承的前面加上virtual就可以避免这些问题。

class Person
{
public:
	string _name;
	int _id;
	int _tel;
	int _adress;
};
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";
	return 0;
}

这样,这个代码就没问题了。

很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂,所以一般不建议设计出多继承,一定不要涉及出菱形继承,否则在复杂度及性能上都有问题。

多继承可以认为是C++的缺陷之一。

在实践中,尽可能的使用多继承,而不是菱形继承。

继承和组合

  • public继承是一种is-a的关系,也就是说每个派生类对象都是一个基类对象
  • 组合式一种has-a的关系,假设B组合了A,每个B对象都有一个A对象
class Tire
{
protected:
	string _brand = "Michelin";//品牌
	size_t _size = 17;//尺寸
};
//组合
class Car
{
protected:
	string colour = "白色";//颜色
	string _num = "陕ABIT00";//车牌号
	Tire _t;
};

你看,在这个里面,轮胎和车并不是is-a的关系,不能说轮胎是车,也不能说车是轮胎,只能说车里面有轮胎。这个就是组合。

在代码关系当中,代码和代码之间的耦合度越低越好,所以,我们尽量使用组合,而不是继承。

虚拟继承解决数据冗余和二义性的原理

为了研究虚拟继承原理,我们给出了一个简化的菱形继承体系,再借助内存窗口观察对象成员的模型。虚拟继承是实现了一个虚表,然后在虚表里面存放了虚函数的地址的指针,然后虚函数在代码段中实现。

好了,本次的文章就到这里了,我们下次再见。 


http://www.kler.cn/news/329662.html

相关文章:

  • 【Redis 源码】7RDB持久化
  • 迈德斯特升降桌使用说明
  • 5个python多线程简单示例
  • 封装轮播图 (因为基于微博小程序,语法可能有些出入,如需使用需改标签)
  • [Day 77] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
  • java往word中添加水印,往excel中添加图片
  • kafka 换盘重平衡副本 操作流程
  • Java面试——操作系统篇
  • 【PCB工艺】表面贴装技术中常见错误
  • 【高效管理集合】并查集的实现与应用
  • springboot3通过HttpRequest请求soap
  • 躺平成长:微信小程序运营日记第二天
  • C0005.Clion中移动ui文件到新目录后,报错问题的解决
  • 『功能项目』宠物的召唤跟随【79】
  • 有关Python时间戳的计算
  • OpenAI全新多模态内容审核模型上线:基于 GPT-4o,可检测文本和图像
  • lstm实践
  • 如何在 Windows 10 上恢复未保存/删除的 Word 文档
  • C++ 学习,标准库
  • 结构光编解码—正反格雷码解码代码
  • SQL_create_view
  • VR、AR、MR、XR 领域最新科研资讯获取指南
  • CSS链接
  • 查找与排序-快速排序
  • 数造科技入选中国信通院《高质量数字化转型产品及服务全景图》三大板块
  • OpenCV透视变换:原理、应用与实现
  • Mysql 学习——项目实战
  • 企业级版本管理工具(1)----Git
  • WPF之UI进阶--完整了解wpf的控件和布局容器及应用
  • 栏目一:使用echarts绘制简单图形