【C+继承】

news2024/11/23 12:17:16

继承

  • 1.继承的概念及定义
  • 2.基类和派生类对象赋值转换
  • 3.继承中的作用域
  • 4.派生类的默认成员函数
  • 5.继承与友元
  • 6.继承与静态成员
  • 7.复杂的菱形继承及菱形虚拟继承
  • 8.继承的总结和反思

1.继承的概念及定义

在这里插入图片描述->继承的概念在这里插入图片描述
继承的本质:就是继承的父类的成员
在这里插入图片描述

->继承的语法
在这里插入图片描述

  • 派生类:子类
  • 基类:父类

在这里插入图片描述->继承父类成员访问方式的变化

在这里插入图片描述

总结:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的
  2. 保护成员限定符是因继承才出现的
  3. public > protected > private
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public
  5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承
  • 考点一:每个对象成员的数据使独立的,并不是完全意义上的“继承”
  • 考点二:父类的私有,子类对象不能直接访问使用,但是可以调用父类成员函数间接使用

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

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。

Student s;
Person p;
//如果子类的对象给与Person呢
p = s;

 //一个子类的对象能不能给父类对象的指针呢?
Person* ptr = &s; 
//一个子类的对象能不能给父类对象的引用呢?
Person& ref = s;  

在这里插入图片描述
基类对象不能赋值给派生类对象:基类的指针或者引用都可以通过强制类型转换赋值给派生类的指针或者引用。但是必须使基类的指针使指向派生类对象时才是安全的

class Person
{
protected :
 string _name; // 姓名
    string _sex;  // 性别
    int _age; // 年龄
};
class Student : public Person
{
public :
 int _No ; // 学号
};
void Test ()
{
	Student sobj ;
	// 1.子类对象可以赋值给父类对象/指针/引用
	Person pobj = sobj ;
	Person* pp = &sobj;
	Person& rp = sobj;
    
 //2.基类对象不能赋值给派生类对象
    sobj = pobj;
    
    // 3.基类的指针可以通过强制类型转换赋值给派生类的指针
    pp = &sobj
    Student* ps1 = (Student*)pp; 
    // 这种情况转换时可以的。
    ps1->_No = 10;
    
    pp = &pobj;	
    Student* ps2 = (Student*)pp; 
 // 这种情况转换时虽然可以,但是会存在越界访问的问
题
    ps2->_No = 10;
}

3.继承中的作用域

  1. 在继承体系中基类派生类都有独立的作用域
  2. 子类成员将屏蔽父类同名成员的直接访问(重定义)
  3. 如果使成员函数的隐藏,需要函数名相同就构成隐藏
  4. 在继承体系里面最好不要定义同名的成员
    在这里插入图片描述

在这里插入图片描述->重载和隐藏的区别

// 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;
	}
};
void Test()
{
	B b;
	b.fun(10);
};

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

在这里插入图片描述

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
    保证派生类对象先清理派生类成员再清理基类成员的顺序。
  5. 派生类对象初始化先调用基类构造再调派生类构造。
  6. 派生类对象析构清理先调用派生类析构再调基类的析构。
  7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲
    解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加
    virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。
class Person
{
public :
 	Person(const char* name = "peter")
 	: _name(name )
 {
 	cout<<"Person()" <<endl;
 }
    
 	Person(const Person& p)
	 : _name(p._name)
 {
	 cout<<"Person(const Person& p)" <<endl;
 }
    
 	Person& operator=(const Person& p )
 {
 	cout<<"Person operator=(const Person& p)"<< 				endl;
 	if (this != &p)
		 _name = p ._name;
        
 	return *this ;
 }
    
 ~Person()
 {
 	cout<<"~Person()" <<endl;
 }
protected :
 	string _name ; // 姓名
};
class Student : public Person
{
public :
 	Student(const char* name, int num)
 	: Person(name )
 	, _num(num )
 	{
 		cout<<"Student()" <<endl;
 	}
 
 	Student(const Student& s)
 		: Person(s)
 		, _num(s ._num)
	 {
 		cout<<"Student(const Student& s)" <<endl ;
 	}
 
 Student& operator = (const Student& s )
 {
	 cout<<"Student& operator= (const Student& s)"		<< endl;
 	if (this != &s)
	 {
 		Person::operator =(s);
 		_num = s ._num;
	 }
 	return *this ;
 	} 
 
 ~Student()
 {
 	cout<<"~Student()" <<endl;
 }
protected :
 int _num ; //学号
	};
		void Test ()
	{	
 Student s1 ("jack", 18);
 Student s2 (s1);
 Student s3 ("rose", 17);
 s1 = s3 ;
}

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

6.继承与静态成员

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

class Person
{
public :
 Person () {++ _count ;}
protected :
 string _name ; // 姓名
public :
 static int _count; // 统计人的个数。
};
int Person :: _count = 0;
class Student : public Person
{
protected :
 int _stuNum ; // 学号
};
class Graduate : public Student
{
protected :
 string _seminarCourse ; // 研究科目
};
void TestPerson()
{
 Student s1 ;
 Student s2 ;
 Student s3 ;
 Graduate s4 ;
 cout <<" 人数 :"<< Person ::_count << endl;
 Student ::_count = 0;
 cout <<" 人数 :"<< Person ::_count << endl;
}

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

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

  • 菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。在Assistant的对象中Person成员会有两份。
class Person
{
public :
 string _name ; // 姓名
};
class Student : public Person
{
protected :
 int _num ; //学号
};
class Teacher : public Person
{
protected :
 int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
 string _majorCourse ; // 主修课程
};
void Test ()
{
 // 这样会有二义性无法明确知道访问的是哪一个
 Assistant a ;
a._name = "peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
 a.Student::_name = "xxx";
 a.Teacher::_name = "yyy";
}
  • 虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和Teacher的继承Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。
class Person
{
public :
 string _name ; // 姓名
};
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 ; // 主修课程
};
void Test ()
{
 Assistant a ;
 a._name = "peter";
}

虚拟继承解决数据冗余和二义性的原理
为了研究虚拟继承原理,我们给出了一个简化的菱形继承继承体系,再借助内存窗口观察对象成员的模型。

class A
{
public:
 int _a;
};
// class B : public A
class B : virtual public A
{
public:
 int _b;
};
// class C : public A
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;
}

8.继承的总结和反思

  1. 很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱
    形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设
    计出菱形继承。否则在复杂度及性能上都有问题。
  2. 多继承可以认为是C++的缺陷之一,很多后来的OO语言都没有多继承,如Java。
  3. 继承和组合
  • public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
  • 组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。
  • 优先使用对象组合,而不是类继承
  • 继承允许你根据基类的实现来定义派生类的实现。这种通过生成派生类的复用通常被称
    为白箱复用(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,基类的
    内部细节对子类可见 。继承一定程度破坏了基类的封装,基类的改变,对派生类有很
    大的影响。派生类和基类间的依赖关系很强,耦合度高。
  • 对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。
  • 实际尽量多去用组合。组合的耦合度低,代码维护性好。不过继承也有用武之地的,有
    些关系就适合继承那就用继承,另外要实现多态,也必须要继承。类之间的关系可以用
    继承,可以用组合,就用组合。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《哈利波特:魔法觉醒》仅16个月欧美停服,引来“阴谋论”

易采游戏网9月11日消息&#xff1a;2022年&#xff0c;当网易宣布将与华纳兄弟合作推出《哈利波特&#xff1a;魔法觉醒》时&#xff0c;全球玩家一片欢腾。不仅在中国市场掀起了一股狂潮&#xff0c;也迅速进入了欧美市场&#xff0c;吸引了无数哈迷和卡牌游戏爱好者。令人始料…

vue+el-table 可输入表格使用上下键进行input框切换

使用上下键进行完工数量这一列的切换 <el-table :data"form.detailList" selection-change"handleChildSelection" ref"bChangeOrderChild" max-height"500"><!-- <el-table-column type"selection" width&quo…

视频融合共享平台LntonAIServer视频分析平台噪声监测优势

LntonAIServer的视频质量诊断功能中的噪声检测是一项关键技术&#xff0c;旨在帮助用户及时发现并解决视频流中的噪声问题&#xff0c;确保视频监控系统的稳定性和可靠性。 在视频监控系统中&#xff0c;噪声问题常常影响到视频画面的清晰度和可用性。噪声可能由多种因素引起&a…

基于SpringBoot+Vue的考研学习分享互助平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的考研学习…

仕考网:省考面试流程介绍,提前了解

省考面试流程介绍&#xff0c;一文带大家了解! 一、面试登记及抽签 考生通常需要提前10至30分钟到达指定地点进行登记。 考试工作人员核对考生身份证和面试通知书等相关证件后&#xff0c;进行抽签确定分组和进场顺序。 二、候考阶段 考生完成抽签后进入候考区等待考试。在…

空气开关跳闸的原因及解决办法

空气开关&#xff08;也称为断路器或空气断路器&#xff09;跳闸通常是因为电路中的某些问题导致的。下面是一些常见的原因及解决办法&#xff1a; 1. 过载 原因&#xff1a;当电路中的电流超过空气开关的额定值时&#xff0c;会导致过载保护动作&#xff0c;使空气开关跳闸。…

银行安全用电典型产品解决方案介绍-安科瑞-叶西平

应用背景 银行作为国家重要部门&#xff0c;是国家经济建设的中枢&#xff0c;也是消防的重点单位。用电安全是银行安全保卫工作 的一个重要环节。银行安保设施、数据中心、自助设施、办公设备等能耗单元对用电的连续性、稳定性和安 全性要求非常高&#xff0c;实时监测线路及…

一文理解单点登录与联合登录

img 如今&#xff0c;许多组织都有大量需要每天进行身份验证的应用程序。用户使用传统意义上的凭据在应用程序进行身份验证时容易遭到社会工程学攻击以及信息泄露风险。 单点登录验证&#xff08;Single Sign-On&#xff09; 单点登录身份验证&#xff0c;无论是内部还是外部…

【LabVIEW学习篇 - 24】:生产者/消费者设计模式

文章目录 生产者/消费者设计模式案例&#xff1a;控制LED等亮灭 生产者/消费者设计模式 生产者/消费者是多线程编程中最基本的一种模式&#xff0c;使用非常普遍。从软件角度看&#xff0c;生产者就是数据的提供方&#xff0c;而消费者就是数据的消费处理方&#xff0c;二者之…

基于51单片机的输液滴速吊瓶控制器proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1fbDdoppvtVdg19H3qI9Vzg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…

中国信通院:《大模型落地路线图研究报告(2024年)》(附下载)

前言 近日&#xff0c;中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;发布《大模型落地路线图研究报告&#xff08;2024年&#xff09;》。 本报告重点梳理了大模型应用落地遵循的诊断、建设、应用、管理四个重要阶段&#xff0c;归纳总结出能力分析、需求挖…

手撕Python之正则

1.正则和re模块的联系 正则表达式是一种通用的用来简洁表达一组字符串的表达式&#xff0c;利用正则表达式可以方便快捷的匹配和筛选字符串 举个例子&#xff1a;在一堆数据中进行电话号码的寻找&#xff0c;我们需要根据电话号码的特征在这一堆数据进行电话的寻找&#xff0…

Oracle 12c 及以上版本补丁更新说明及下载方法

参考下面的文章&#xff0c;会对补丁更新的流程有一定的了解。 https://www.modb.pro/db/27255 RU&#xff08;Release Updates&#xff09;是每一个季度的版本升级。包括&#xff1a; 最新的BUG修复最新的安全漏洞补丁最新添加的功能 以19c为例&#xff0c;对应的升级版本升…

太全面了,各种3D​模型和资源都开源了

太全面了&#xff0c;各种3D​模型和资源都开源了 想在三维图形世界中畅游&#xff1f;three-cesium-examples 是一个开源的 three.js 和 cesium.js 案例与演示社区&#xff0c;让你轻松掌握这些酷炫的技术&#xff01;本文将带你了解这个仓库的主要内容、特点&#xff0c;并教…

最通俗的语言搞懂”大模型“的来龙去脉

人工智能时代&#xff0c;有很多时髦、相互容易混淆概念的科技名词&#xff1a;AI、Machine Learning、Deep Learning、Generative AI、Large Model&#xff0c;它们指的是同一个概念么&#xff1f;不是的。 AI&#xff08;artificial intelligence人工智能&#xff09;&#x…

如何避免 Java 学习中误用 break 和 continue?

在 Java 编程学习过程中&#xff0c;许多初学者经常会误用 break 和 continue 语句。这种情况不仅影响代码的可读性&#xff0c;还可能导致逻辑错误&#xff0c;从而使程序无法按预期工作。 一、break 和 continue 的基本概念 1.1 break 语句 break 语句在 Java 中用于立即终…

【资料集】软件资料合集整理,软件项目全生命周期各阶段文档

在软件开发过程中&#xff0c;文档扮演着至关重要的角色。它不仅记录了项目的需求、设计和开发过程&#xff0c;还为项目的维护和管理提供了便利。本文将详细介绍软件开发文档的重要性和作用&#xff0c;以及需求分析、软件设计、开发过程、运维管理和项目管理等方面的文档编写…

LabVIEW高效换热器性能试验系统

随着能源和化工行业对换热器性能提出更高要求&#xff0c;开发了一种基于LabVIEW的换热器性能试验装置测控系统的开发&#xff0c;该系统集成了实时测量、分析、调节等功能&#xff0c;能够精确控制和测试换热器的性能&#xff0c;以支持新品开发和改进设计。 项目背景&#xf…

汽车智能座舱展︱2025 广州国际汽车智能座舱及车载显示技术展览会

汽车智能座舱展︱2025 广州国际汽车智能座舱及车载显示技术展览会 China Guangzhou Automotive Smart Cockpit and Dispaly Technology Expo 2025 时间&#xff1a;2025年11月20日-22日 地点&#xff1a;广州保利世贸博览馆 (PWTC Expo) 亚洲领先的汽车智能座舱及车载显示…

Brave编译指南2024 Windows篇:安装Visual Studio 2022(二)

1.引言 在编译Brave浏览器之前&#xff0c;安装和配置合适的开发工具是至关重要的一步。Visual Studio 2022是编译Brave浏览器所需的重要开发环境&#xff0c;它提供了一整套工具和服务&#xff0c;以支持多种编程语言和技术。作为一款功能强大的集成开发环境&#xff08;IDE&…