C++:继承及其相关问题

继承的定义

继承机制是⾯向对象程序设计实现代码复⽤的重要⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法 (成员函数) 和属性 (成员变量),从而产⽣的类,这样的类称为派⽣类,也称为子类。而这样的类就成为 基类 / 派生类 或 父类 / 子类 。

class Person
{
public:
	void Print()
	{
		cout << "void Print()" << endl;
	}

private:
	string name;
	string tel;
	int age;
};

class Student : public Person
{
public:

private:
	string id;
};

继承的格式

继承父类成员的访问方式

继承了父类的子类中可以使用父类的 public 、protected 的变量和函数,但值得注意的是,虽然子类不可以使用父类的 private 的成员变量和函数,但子类中包含父类的 private 的成员变量和函数,只是不能使用。

此外,如果未指定继承方式,则使用关键字 class 时默认为 private,使用关键字 struct 时默认为 public。

类模板的继承

之前在模拟实现 stack 时,我们使用适配器模式,来实现顺序栈或链栈,而继承也可以达到类似的效果。但要注意基类是类模板时,需要指定⼀下类域,否则会报错。

template<class T>
class stack : public std::vector<T>
{
public:
	void push(const T& x)
	{
		vector<T>::push_back(x);
	}

	void pop()
	{
		vector<T>::pop_back();
	}
};

因为模版是按需实例化,在 stack 实例化时,vector 也会实例化,如果不指定类域,push_back等成员函数不会被实例化,从而导致出错。

基类与派生类的赋值兼容转换:切片操作

在C++中,当派生类对象被赋值给基类的指针或引用时,会发生派生类对象向基类对象的赋值兼容转换。不同于类型转换,其会直接指向的是派⽣类中切出来的基类那部分(因此称之为切片)。这意味着可以将派生类的地址赋给基类指针,或者将派生类对象赋给基类对象。

Student stu;

Person* p = &stu;
Person& p1 = stu;

继承的隐藏机制

如果基类和派生类中有同名的成员时,派⽣类成员将会屏蔽基类对同名成员的直接访问,这种现象称为隐藏。如果要访问基类的同名成员,就要指定类域。还要注意的一点是,派生类和基类如果出现同名函数,则只要函数名相同就构成隐藏。

class Person
{
public:
	void Print()
	{
		cout << "void Print()" << endl;
	}

private:
	string name;
	string tel;
	int age;
};

class Student : public Person
{
public:
	void Print(int i = 1)
	{
		cout << "void Print(int i = 1)" << endl;
	}

private:
	string id;
};

int main()
{
	Student stu;

	stu.Print();
	stu.Person::Print();

	return 0;
}

派生类的默认成员函数

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{}

	Person(const Person& p)
		: _name(p._name)
	{}

	Person& operator=(const Person& p)
	{
		if (this != &p)
		{
			_name = p._name;
		}

		return *this;
	}

	~Person()
	{}


private:
	string _name;
};

构造函数

派⽣类的构造函数必须调⽤基类的构造函数初始化基类的那⼀部分成员。如果有默认构造,会自动调用。如果基类没有默认的构造函数,则必须在派⽣类构造函数的初始化列表阶段显示调⽤。

其显示调用时需要使用类名来访问。

class Student : public Person
{
public:
	Student(const char* name, int id)
		: Person(name)
		, _id(id)
	{}

private:
	int _id;
};

拷贝构造

派⽣类的拷⻉构造函数必须调⽤基类的拷⻉构造完成基类的拷⻉初始化。

class Student : public Person
{
public:
	Student(const char* name, int id)
		: Person(name)
		, _id(id)
	{}

	Student(const Student& s)
		: Person(s)
		, _id(s._id)
	{}

private:
	int _id;
};

赋值重载

派⽣类的 operator= 必须要调⽤基类的 operator= 才能完成基类的复制。需要注意的是派⽣类的 operator= 与基类的 operator= 构成了隐藏,所以调⽤基类的 operator= 时,需要指定基类作用域。

class Student : public Person
{
public:
	Student(const char* name, int id)
		: Person(name)
		, _id(id)
	{}

	Student(const Student& s)
		: Person(s)
		, _id(s._id)
	{}

	Student& operator = (const Student& s)
	{
		if (this != &s)
		{
			// 会构成隐藏,所以需要显⽰调⽤ 
			Person::operator =(s);
			_id = s._id;
		}
		return *this;
	}

private:
	int _id;
};

析构函数

派⽣类的析构函数不需要显示调用基类的析构函数,其会在析构派生类后,自动调⽤基类的析构函数清理基类成员。这样才能保证先清理派生类对象,再清理基类成员的顺序(因为基类可能还会被其他派生类继承,不能先清理基类)。

class Student : public Person
{
public:
	Student(const char* name, int id)
		: Person(name)
		, _id(id)
	{}

	Student(const Student& s)
		: Person(s)
		, _id(s._id)
	{}

	Student& operator = (const Student& s)
	{
		if (this != &s)
		{
			// 构成隐藏,所以需要显⽰调⽤ 
			Person::operator =(s);
			_id = s._id;
		}
		return *this;
	}

	~Student()
	{}

private:
	int _id;
};

final 关键字

添加了 final 的类不能被继承,否则会报错。

// 不能被继承
class Person final
{
public:

private:
	string _name;
};

静态成员与继承的关系

基类中定义的 static 成员,无论被继承多少次,其都只有一份,存储在静态区中。一般直接通过类名访问,也可以通过实例的对象访问。

class Person
{
public:
	static int i;

private:
	string _name;
};

int Person::i = 1;

class Student : public Person
{
public:

private:
	int _id;
};

int main()
{
	Person::i++;
	Student::i++;

	Person per;
	Student stu;

	per.i++;
	stu.i++;

	return 0;
}

多继承

⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯。

C++支持多继承,被继承的多个类之间用逗号进行分隔。

class Fruit
{

};

class Vegetables
{

};

// 多继承
class Tomato : public Fruit, public Vegetables
{

};

C++ 多继承出现的问题及解决方法

出现的问题:菱形继承

菱形继承是多继承的⼀种特殊情况。⽀持多继承就⼀定会有菱形继承的出现。

class Food
{
public:
	string name;
};

class Fruit : public Food
{

};

class Vegetables : public Food
{

};

class Tomato : public Fruit, public Vegetables
{

};

菱形继承会出现数据冗余和⼆义性的问题,在 Tomato 的对象中 Food 成员会有两份,在调用其成员 name 时,会有指向不明确的错误,必须指定类域才能解决。

解决方法:虚继承

virtual 是定义C++中虚函数的关键字,在会出现菱形继承的地方添加 virtual 就可以解决菱形继承出现的的问题。

class Food
{
public:
	string name;
};

class Fruit : virtual public Food
{

};

class Vegetables : virtual public Food
{

};

class Tomato : public Fruit, public Vegetables
{

};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/906379.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Centos7.9 x86架构部署

一、部署环境 表 1‑1 环境服务版本号系统centos7.9_2009运行环境1JDK1.8_321前端WEBNginx1.14数据库postgresqlpostgresql13postgis3.1pgrouting3.1消息队列rabbitmq3.8.16运行环境2erlang23.3.3.1 二、部署JDK 2.1下载JDK安装包 官网下载JDK8 官网地址&#xff1a; https…

【uniapp3】分享一个自己写的h5日历组件

简言 分享一下自己基于uniapp写的日历组件。如果不太满足你的需求&#xff0c;可以自己改造。 日历 实现分析&#xff1a; 页面显示 - 分为顶部显示和日历显示&#xff0c;我这里做了多行和单行显示两种情况&#xff0c;主要是当时看着手机的日历做的&#xff0c;手机上的…

Nginx安装配置详解

Nginx Nginx官网 Tengine翻译的Nginx中文文档 轻量级的Web服务器&#xff0c;主要有反向代理、负载均衡的功能。 能够支撑5万的并发量&#xff0c;运行时内存和CPU占用低&#xff0c;配置简单&#xff0c;运行稳定。 写在前 uWSGI与Nginx的关系 1. 安装 Windows 官网 Stabl…

Java版企电子招标采购系统源业码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

MS01SF1 精准测距UWB模组助力露天采矿中的人车定位安全和作业效率提升

在当今矿业行业&#xff0c;随着全球对资源需求的不断增加和开采难度的逐步提升&#xff0c;传统的作业方式面临着越来越多的挑战。露天矿山开采&#xff0c;因其大规模的作业环境和复杂的地形特点&#xff0c;面临着作业人员的安全风险、设备调度的高难度以及资源利用率低下等…

【Web.路由】——路由模板

路由模板负责根据规则生成URL&#xff0c;从而使得请求可以正常访问到资源。 总之就是——》》》 规范如何写一个url&#xff0c;并且命名以方便进行管理。 在Asp.net core中的Http管道机制&#xff0c;UseRouting()和 UseEndpoints()这两个中间件来实现整个路由系统。关于asp…

c加加11第二弹~

1lambda 1.1.lambda表达式书写格式 [capture-list] (parameters) mutable -> return-type { statement} 1.2lambda表达式各部分说明 [capture-list] : 捕捉列表&#xff0c;该列表总是出现在lambda函数的开始位置&#xff0c;编译器根据[]来判断接下来的代码是否为lamb…

记录|多线程和异步简单理解

目录 前言一、单线程二、多线程-Thread多线程是都多少个的时候会导致性能变差 三、多线程-Task类Task的优势 四、异步- awaitawait注意&#xff1a;多个Task Run()天剑await后&#xff0c;变成了同步执行解决方法 更新时间 前言 参考视频&#xff1a;C#基础教程 多线程编程入门…

凸极式发电机的相量图分析和计算,内功率因数角和外功率因数角和功角的定义。

图1&#xff1a;同步发电机稳态相量图 若发电机为凸极式&#xff0c;由于凸极机正、交轴同步电抗不等&#xff0c;即xd≠xq&#xff0c;因此必须先借助虚构电动势 E ˙ Q E ˙ q − ( x d − x q ) I ˙ d \dot{E}_Q\dot{E}_q-(x_d-x_q)\dot{I}_d E˙Q​E˙q​−(xd​−xq​)…

C语言原码、反码和补码的详解

C语言原码、反码和补码的详解 放在最前面的1、前言正数的原码、反码和补码负数的原码、反码和补码 2、整数的原码&#xff08;2.1&#xff09;原码的定义&#xff08;2.2&#xff09;计算原码 3、整数的反码&#xff08;3.1&#xff09;反码的定义&#xff08;3.2&#xff09;计…

idea 导入Spring源码遇到的坑并解决

1.下载相关文件 通过百度网盘分享的文件&#xff1a;Spring 链接&#xff1a;https://pan.baidu.com/s/1r9rkGOCaY9SFn9ecng5cIg?pwd8888 提取码&#xff1a;8888 2.配置gradle环境 gradle下载地址 需要翻墙下 https://services.gradle.org/distributions/ 我选择的是 grad…

Redis-“自动分片、一定程度的高可用性”(sharding水平拆分、failover故障转移)特性(Sentinel、Cluster)

文章目录 零、写在前面一、水平拆分(sharding/分片)、故障转移(failover)机制介绍水平拆分&#xff08;Sharding&#xff09;故障转移机制 二、Redis的水平拆分的机制有关的配置1. 环境准备2. 配置文件配置3. 启动所有Redis实例4. 创建集群5. 测试集群读/写6. 集群管理 三、Red…

C++STL详解(九)map和set的使用

一.关联式容器的介绍 CSTL包含了序列式容器和关联式容器&#xff1a; 序列式容器里面存储的是元素本身&#xff0c;其底层是线性的数据结构&#xff0c;就譬如我们之前学习的vector&#xff0c;list&#xff0c;deque等等。关联式容器里面存储的是<key,value>的键值对&…

goframe开发一个企业网站 模版界面4

###goframe已有了模板的功能 {{"string"}} // 一般 string {{raw string}} // 原始 string {{c}} // byte {{print nil}} // nil 也被支持 {{. | FuncA | FuncB | FuncC}}{{if .condition}}... {{else}}{{if .condition2}}...{{end}} {{end}}{{rang…

一、k8s快速入门之学习Kubernetes组件基础

一、三个容器管理器平台 Apache MESOS 开源的分布式资源管理框架&#xff0c;被推特选为基础平台&#xff0c;2019年推特换位k8s&#xff0c;MESOS最新版可以在MESOS上管理k8sDOCKER SWARM docker总部发行的&#xff0c;实现docker的集群方案&#xff0c;和docker捆版一起&…

初始JavaEE篇——多线程(7):定时器、CAS

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaEE 目录 定时器的使用 定时器的原理 模拟实现定时器 CAS 介绍 CAS的应用场景 解析 AtomicInteger 类 实现自旋锁 CAS的缺陷…

【UGUI】为射击游戏添加动态显示的分数和血量到UI界面

项目背景 在这个项目中&#xff0c;我们希望实现一个简单的游戏系统&#xff0c;其中玩家可以通过击中目标来获得分数&#xff0c;同时通过与怪物碰撞来减少血量。分数和血量需要在游戏界面上实时显示&#xff0c;以便玩家能够随时了解自己的状态。 技术实现 1. 静态变量的使…

stm32引脚PB3、PB4、PA15作为普通IO口用时,需要先解除调试端口复用

当项目调试的时候&#xff0c;发现PA15引脚无论配置输出高还是低或者输入&#xff0c;均只能输出3.3V的高电平。 目前STM的硬件调试有两种方法&#xff0c;JTAG和SW的方式&#xff0c;目前个人认为最好的方式就是SW&#xff0c;因为它只占用PA13和PA14两个IO。而JTAG还要多占用…

MATLAB与STK互联:仿真并获取低轨卫星与指定区域地面站的可见性数据

MATLAB控制STK实现&#xff1a;仿真并获取低轨卫星与指定区域地面站的可见性数据 本次仿真主要参考了多篇文献和网站&#xff0c;包括但不限于&#xff1a;《Using MATLAB for STK Automation》、CSDN博文&#xff1a; 拜火先知的博客_CSDN博客-笔记、AGI官网有关MATLAB的内容…

用Python设置、更新和获取Excel单元格的值

Excel工作簿作为一款广泛使用的数据管理工具&#xff0c;与Python相结合&#xff0c;可以使得自动化处理大量数据成为可能。通过Python来设置、更新以及读取Excel单元格的值&#xff0c;不仅可以极大地提高工作效率&#xff0c;减少重复劳动&#xff0c;还能增强数据处理流程的…