C++ 继承

一. 继承的概念与定义

1.1. 继承的概念

继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段,它允许程序员在
持原有类特性的基础上进行扩展 ,增加功能,这样产生新的类,称派生类。继承 呈现了面向对象
程序设计的层次结构 ,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,
承是类设计层次的复用。
class A
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "peter"; int _age = 18; 
};// 继承后父类的A的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了
Student和Teacher复用了A的成员。我们使用监视窗口查看Student和Teacher对象,可
以看到变量的复用。调用Print可以看到成员函数的复用。
class Student : public A
{
protected:int _stuid; 
};class Teacher : public A
{
protected:int _jobid;
};int main()
{Student s;Teacher t;s.Print();t.Print();return 0;
}

1.2. 继承格式

继承格式:

class Student(派生类) : public(继承方式) Person(基类)

{

public:

        int _studi;

        int _major;

}

继承关系和访问限定符:

 继承基类成员访问方式的变化:

类成员/继承方式public继承protected继承private继承
基类的public成员派生类public成员派生类protected成员派生类private成员
基类的protected成员派生类protected成员派生类protected成员派生类private成员
基类的private成员在派生类中不可见在派生类中不可见在派生类中不可见
// 实例演示三种继承关系下基类成员的各类型成员访问关系的变化  
class Person
{
public :void Print (){cout<<_name <<endl;}
protected :string _name ; // 姓名
private :int _age ; // 年龄
};//class Student : protected Person
//class Student : private Person
class Student : public Person
{
protected :int _stunum ; // 学号
};

二. 基类和派生类对象的赋值转化

  • 派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用 。这里有个形象的说法叫切片
    或者切割。寓意把派生类中父类那部分切来赋值过去。
  • 基类对象不能赋值给派生类对象。
  • 基类的指针或者引用可以通过强制类型转化赋值给派生类 的指针是指向派生类对象时才是安全的。这里基类如果是多态类型,可以使用 RTTI(Run- Time Type Information) dynamic_cast 来进行识别后进行安全转换。

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 = &sobjStudent* ps1 = (Student*)pp; // 这种情况转换时可以的。ps1->_No = 10;pp = &pobj;Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题ps2->_No = 10;
}

三. 继承中的作用域

  1. 在继承体系中 基类 派生类 都有 独立的作用域
  2. 子类和父类中有同名成员, 子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,
    也叫重定义。 (在子类成员函数中,可以 使用 基类 :: 基类成员 显示访问)。 
  3.  需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
  4. 注意在实际中在 继承体系里 面最好 不要定义同名的成员
// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是非常容易混淆
class Person
{
protected :string _name = "小李子"; // 姓名int _num = 111;   // 身份证号
};class Student : public Person
{
public:void Print(){cout<<" 姓名:"<<_name<< endl;cout<<" 身份证号:"<<Person::_num<< endl;cout<<" 学号:"<<_num<<endl;}
protected:int _num = 999; // 学号
};void Test()
{Student s1;s1.Print();
};

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

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
    的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  3.  派生类的operator=必须要调用基类的operator=完成基类的复制。
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
    保证派生类对象先清理派生类成员再清理基类成员的顺序
  5.   派生类对象初始化先调用基类构造再调派生类构造。
  6.  派生类对象析构清理先调用派生类析构再调基类的析构。
  7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同。 那么编译器会对析构函数名进行特殊处理,处理成 destrutor() ,所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。
  8. 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 ;
    }

五. 继承与友元

友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。

//类的声明,防止编译器在Person类中找不到Student类
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;
}int main()
{Person p;Student s;Display(p, s);
}

六. 继承与静态成员

基类定义了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.1. 单继承

单继承:一个子类只有一个直接的父类的继承关系。

class A
{
private:int _a = 1; 
}class B : public A
{
private:int _b = 2;
}

 7.2. 多继承

多继承:一个子类有两个以及两个以上的父类的继承关系。

class A
{
private:int _a = 1;
}class B
{
private:int _b = 2;
}class C : public A, public B
{
private:int _c = 3;
}

7.3. 菱形继承

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

菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。
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";
}

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

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

相关文章

【启程Golang之旅】深入理解 Protocol Buffers 及其应用

如果你是 Go 语言的开发者&#xff0c;理解如何在 Go 中使用 Protobuf&#xff0c;将帮助你大幅提升数据传输的效率&#xff0c;并实现更高性能的系统设计。 本篇文章将深入探讨 Go 语言中使用 Protobuf 的基础知识、常见应用以及最佳实践&#xff0c;带你一步步了解如何在项目…

vue3.5+版本 defineProps响应式解构,保留数据响应式

正确写法&#xff1a;直接通过 defineProps 结构可以保留响应式 let {num:numNew} defineProps({num: {} }) console.log(具有响应式,numNew); 错误写法&#xff1a;这样会丢失响应式 const props defineProps({num: {} }) let {num:numNew} props console.log(会丢失响…

直播 鸿蒙5.0面试必修技能之鸿蒙性能优化技术

一&#xff1a;行业分析&#xff1a; PC时代---互联网---移动互联网---大数据/人工智能---物联网 c/c/java/php--- andorid/ios/前端/hadoop(存储)/spark/flink【12-14年】 --- ArkTS 李兴平 hao123.com/ 网站:6w/day 06年 5000w卖给了百度 盛大传奇/ 腾讯 互联…

怎么能更好的通过驾考呢?

充分准备&#xff1a; 提前了解驾考内容和要求&#xff0c;包括理论知识、场地驾驶技能、道路驾驶技能和安全文明驾驶常识等。合理安排学习时间&#xff0c;确保有足够的时间进行学习和练习。理论学习&#xff1a; 认真阅读和理解驾考相关书籍和资料&#xff0c;特别是交通法规…

Notion + Python + scholarly = 超强文献管理助手

摘要&#xff1a;在科研文献管理中&#xff0c;研究人员常常需要维护自己的文献数据库&#xff0c;我使用 Notion-database 作为的文献数据库管理工具&#xff08;开源模板&#xff09;。Notion-based 的方法无法实时更新文章的引用量信息。我结合了 Notion Integration 和 sch…

Git遇到“fatal: bad object refs/heads/master - 副本”问题的解决办法

Git遇到“fatal: bad object refs/heads/master - 副本”问题的解决办法 起源 让我们从一个常见的Git错误开始&#xff1a; fatal: bad object refs/heads/master - 副本这个错误提示通常意味着Git在引用&#xff08;ref&#xff09;中发现了不一致或损坏的数据。引用是Git用…

LinkedIn怎么养号:2024最新养号技巧揭秘

LinkedIn领英作为全球最大的职场社交平台&#xff0c;是跨境外贸企业与潜在客户、业务伙伴和同事进行交流的重要平台。然而&#xff0c;许多人在注册和使用LinkedIn时&#xff0c;常常会遇到账户受限甚至被封的困扰。想要拥有一个安全稳定的LinkedIn账户&#xff0c;养号是必不…

RHCE—web服务器

一、web服务器简介 web服务器一般指的是“网站服务器”&#xff0c;是某种驻留在因特网上的计算机程序&#xff0c;可以向请求终端提供服务&#xff0c;主要功能时存储、处理和传递网页给“客户”&#xff0c;传递内容一般是HTML文档、图像、样式表或脚本等&#xff0c;也可以…

块存储、文件存储和对象存储详细介绍

块存储、文件存储和对象存储介绍 块存储&#xff1a;像跑车&#xff0c;因为它们都能提供快速的响应和高性能&#xff0c;适合需要即时数据访问的场景&#xff0c;比如数据库和虚拟化技术。 文件存储&#xff1a;像货车&#xff0c;因为它们都能承载大量货物&#xff08;文件&…

ARM base instruction -- umaddl

Unsigned Multiply-Add Long multiplies two 32-bit register values, adds a 64-bit register value, and writes the result to the 64-bit destination register. 将两个32位寄存器值相乘&#xff0c;添加一个64位寄存器值&#xff0c;并将结果写入64位目标寄存器。 64-bit…

bossplayersCTF: 1 靶场渗透

靶场&#xff1a;bossplayersCTF: 1 bossplayersCTF: 1 ~ VulnHubhttps://www.vulnhub.com/entry/bossplayersctf-1,375/ 攻击机&#xff1a;kali-linux-2024 第一部分&#xff1a;信息收集 1,将两台虚拟机网络连接都改为NAT模式&#xff0c;并查看靶机的MAC地址 2&#xff0c;…

【linux学习指南】磁盘分区挂载到目录,形成文件系统挂载点

文章目录 &#x1f4dd;前言&#x1f320; 查看系统分区&#x1f309;制作一个大的磁盘块&#xff0c;就当做一个分区&#x1f309;格式化写入文件系统&#x1f309;将分区挂载到指定的目录&#x1f309;在分区重创建文件&#x1f309;卸载分区&#x1f309;分区挂载到目录才能…

STM32CUBEIDE FreeRTOS操作教程(八):queues多队列

STM32CUBEIDE FreeRTOS操作教程&#xff08;八&#xff09;&#xff1a;queues多队列 STM32CUBE开发环境集成了STM32 HAL库进行FreeRTOS配置和开发的组件&#xff0c;不需要用户自己进行FreeRTOS的移植。这里介绍最简化的用户操作类应用教程。以STM32F401RCT6开发板为例&#…

redis 原理篇 25 网络模型 信号驱动IO 及 异步IO

剩下这两种&#xff0c;用得少&#xff0c;快速过一下&#xff0c; 说啥队列太小&#xff0c;这个不是问题&#xff0c;搞个持久化&#xff0c; 说啥队列元素太频繁导致开销大&#xff0c;这个也没问题&#xff0c;搞成批量入队&#xff0c;减少频率&#xff0c;增大吞吐量&am…

某事业单位转型公益二类后岗位梳理项目纪实

某事业单位转型公益二类后岗位梳理项目纪实 ——公益一类事业单位转型二类后&#xff0c;如何优化岗位配置&#xff0c;梳理岗位职责 【客户行业】事业单位 【问题类型】岗位梳理 【客户背景】 某地公证机构于20世纪90年代经批准设立&#xff0c;是该市司法局直属国家公证…

DNS域名解析服务器--RHCE

1.DNS简介 DNS &#xff08; Domain Name System &#xff09;是互联网上的一项服务&#xff0c;它作为将域名和 IP 地址相互映射的一个分布式 数据库&#xff0c;能够使人更方便的访问互联网 DNS 系统使用的是网络的查询&#xff0c;那么自然需要有监听的 port 。 DNS 使用的是…

Linux案例:DNS服务器配置

Linux案例&#xff1a;DNS服务器配置 实验一&#xff1a;正向解析 服务端配置&#xff1a; [rootserver ~]# setenforce 0 [rootserver ~]# nmcli c modify ens160 ipv4.method manual ipv4.addresses 192.168.70.131/24 ipv4.gateway 192.168.70.2 ipv4.dns 114.114.114.11…

京东创作平台旋转验证码识别

昨天京东创作平台验证码又更新了&#xff0c;变成了这种旋转验证码。经过我们一天的努力&#xff0c;终于完成了这款验证码的数据标记&#xff0c;模型训练。现在正确率达到了几乎100%。 识别代码 只需要获取图片链接&#xff0c;下载图片得到原图&#xff0c;使用下面代码就可…

Spring DispatcherServlet详解

文章目录 Spring DispatcherServlet详解一、引言二、DispatcherServlet的初始化与工作流程1、DispatcherServlet的初始化1.1、加载配置和建立WebApplicationContext1.2、初始化策略 2、DispatcherServlet的工作流程2.1、请求分发2.2、代码示例 三、总结 Spring DispatcherServl…

Ubuntu 安装CUDA, cuDNN, TensorRT(草稿)

文章目录 写在前面一、CUDA, cuDNN, TensorRT 三个库的版本的确定二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04, 本文安装的版本&#xff1a; cuda_11.1.0&#xff1b;cuDNN-8.2.1&#xff1b;TensorRT-8.2.4.2 一、CUDA, cuDNN, TensorRT 三个库…