C++-继承

目录

一、继承的概念和定义

1、继承概念

 2、继承的语法格式

 3、继承的方式

4、继承类模板

二、基类和派生类之间的转换

三、继承中的作用域

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

一、默认成员函数介绍

1、派生类中基类成员的构造

2、派生类中基类成员拷贝构造

3、复制重载

4、析构

 二、实现一个无法被继承的类

五、继承与友元

六、继承与静态成员

七、多继承及菱形继承问题

1、虚继承

八、继承与组合


一、继承的概念和定义

1、继承概念

在C++中,继承是面向对象编程的一个重要特性。它允许创建一个新类(派生类),从一个现有的类(基类)继承属性和行为。简单地说,派生类是基类得一种特殊化,它继承了基类的成员变量和成员函数,并且可以在这个基础上添加新的成员或者修改从基类继承来的成员的行为;

###例:现有两个类,学生类和老师类,学生和老师都是人,他们有着某些相同的变量和行为,但是也有不同的;此时我们定义一个人类,这个人类有着学生和老师类相同的成员函数和成员变量,那么我们在写学生或者老师类的时候就可以直接继承人类,此时学生类和老师类就有了人类里面的函数和变量;当然学生或者老师它们也有自己的成员和变量;

已知的老师和学生类的定义:

class Teacher
{
public:void identity()//确认身份{cout << "Teacher identity" << endl;}void teach()   //行为{cout << "teach" << endl;}
protected:string _name;  //姓名string _add;   //地址string _tel;   //电话int _age;      //年龄string _title; //职称
};class Student : public Person
{
public:void identity()//确认身份{cout << "Student identity" << endl;}void study()   //行为{cout << "study" << endl;}
protected:string _name;  //姓名string _add;   //地址string _tel;   //电话int _age;      //年龄int _stuid;    //学号
};
int main()
{Student s1;Teacher t1;s1.identity();cout << endl;t1.identity();return 0;
}

继承了人这个类的老师类和学生类的定义:

class Person
{
public:void identity(){cout << "Preson identity" << endl;}
protected:string _name;  //姓名string _add;   //地址string _tel;   //电话int _age;      //年龄
};class Teacher : public Person
{
public:void teach()   //行为{cout << "teach" << endl;}
protected:string _title; //职称
};class Student : public Person
{
public:void study()   //行为{cout << "study" << endl;}
protected:int _stuid;    //学号
};
int main()
{Student s1;Teacher t1;s1.identity();cout << endl;t1.identity();return 0;
}

 2、继承的语法格式

Person叫做基类或者父类,Student和Teacher叫做派生类或者子类;继承要在子类的后面加冒号再写上继承的父类;

 3、继承的方式

继承分为public、protected、private;这几种继承方式的不同体现在子类中对父类属性或者行为的访问权限:

  • 当继承方式是private时,子类不能在类外或者类内直接访问父类的属性或者行为,无论是哪种访问限定符修饰的属性或者行为,但是父类的行为和属性还是被继承到子类中了;
  • protected继承:父类中的public或者protected访问限定符修饰的在子类中的访问权限全部变为protected;若是想父类中的不被类外部访问,但是想要被子类访问,就把父类中的属性或者行为的访问限定符写作protected;可以得知protected就是为了继承而生的;
  • 继承时可以不写继承的方式。那么class默认为private继承;struct默认为pubilc继承;

4、继承类模板

继承类模板就是继承一个模板类,大框架和普通的继承相同,但是调用父类中的属性或者行为时要指定在父类的哪个属性或者行为,这样是因为类模板的按需实例化,不指定就不会实例化,会报错;

###示例:用继承写一个栈,这个栈继承了父类vector

#include<iostream>
#include<vector>
using namespace std;namespace S
{template<class T>class stack :public vector<T>{public:void push(const T& val){vector<T>::push_back(val);}void pop(){vector<T>::pop_back();}T& top(){return vector<T>:: back();}bool empty()const{return vector<T>:: empty();}};
}
int main()
{S::stack<int> s;s.push(1);s.push(2);s.push(3);while (!s.empty()){cout << s.top() << endl;s.pop();}return 0;
}

每次复用vector里面的成员函数时都要指定父类类域,否则报错,找不到标识符;


二、基类和派生类之间的转换

  • 基类和派生类之间的转换时发生在public继承中的;
  • 转换指的是派生类的对象可以被赋值给基类的对象、引用、指针;有个形象的说法叫做切片,就是把派生类里面基类的部分给基类对象;
  • 基类对象不能被赋值给派生类;
#include<iostream>
#include<string>
using namespace std;class Person
{
protected:string _name;string _gender;int _age;
};
class Student :public Person
{
protected:int _id;
};
void test1()
{Student s1;Person p1 = s1;Person& p2 = s1;Person* p3 = &s1;
}

 父类对象被子类赋值之后,只含有切片过来的成员,并且对象的成员变量的值都相同;

但是反过来就不可以; 


三、继承中的作用域

  • 基类和派生类都有其独立的作用域;
  • 基类中和派生类中有相同名称的属性时,派生类将不会访问到这个属性,这叫做隐藏;
  • 当基类中和派生类中的函数名相同时,也形成隐藏关系(只要函数名相同就构成这种关系)
  • 当构成隐藏关系时,想要在派生类中访问到基类中的被隐藏的属性或者行为时,要指定基类类域;
  • 一般不建议写成含有隐藏关系的基类和派生类

###代码示例:

class Person
{
protected:int _num = 111;string _name = "Lois";
};
class Student:public Person
{
public:void Print(){//基类中的_num被隐藏,只能找到派生类中的_numcout << "姓名:" << _name << endl;cout << "号码:" << _num << endl;//想要访问基类中的_num,需要指定类域cout << "号码:" << Person::_num << endl;}
protected:int _num = 999;
};
void test2()
{Student s1;s1.Print();
}

只要基类和派生类中函数名相同就构成隐藏关系

###代码示例:

class Person
{
public:void func(int a){cout << "Person func" << endl;}
};
class Student :public Person
{
public:void func(){cout << "Student func" << endl;}
};

 通过派生类访问不到基类中的func,只能访问到派生类中的


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

一、默认成员函数介绍

可以把基类当作派生类中的一个自定义类型的属性,这个属性和string类似要调用自己的默认成员函数

1、派生类中基类成员的构造

在派生类中,会调用基类自己的默认构造函数来构造派生类中从基类继承过来的属性,若是基类没有默认构造,那么基类有传参构造函数时,在派生类中要传参构造基类成员;

其他的普通类里面的构造规则一样;

###代码示例:

	class Person
{
public:Person(string name = "Peter"):_name(name){}//Person(string name)//	:_name(name)//{}
protected:string _name;
};class Student :public Person
{
public:Student(string name="Peter",int age = 19):Person(name),_age(age){}
protected:int _age;
};
void test3()
{Student s1;
}

2、派生类中基类成员拷贝构造

当用一个派生类对象去拷贝构造另一个派生类对象时,对于基类部分的成员变量的拷贝要去调用基类自己的拷贝构造函数

###代码示例:

class Person
{
public:Person(string name = "Peter"):_name(name){}Person(const Person& p):_name(p._name){cout << "基类拷贝构造" << endl;}
protected:string _name;
};class Student :public Person
{
public:Student(string name="Peter",int age = 19):Person(name),_age(age){}Student(const Student& s):Person(s)//对于基类部分调用基类的拷贝构造函数,_age(s._age){cout << "派生类拷贝构造" << endl;}
protected:int _age;
};
void test3()
{Student s1("Tom", 18);Student s2 = s1;
}

这里的用到了基类和派生类之间的转换,也就是切片,s是派生类,直接给p; 

 

3、复制重载

当两个派生类进行赋值操作时,对于基类部分的赋值需要调用基类的赋值重载函数 ;值得注意的是因为派生类和基类的复制重载函数名相同,所以要进行指定类域;

###代码示例:

class
{
public:Person(string name = "Peter"):_name(name){}void operator=(const Person& p){if (this != &p){_name = p._name;}cout << "基类赋值重载" << endl;}
protected:string _name;
};class Student :public Person
{
public:Student(string name = "Peter", int age = 19):Person(name), _age(age){}void  operator=(const Student& s){if (this != &s){Person::operator=(s);_age = s._age;}cout << "派生类赋值重载" << endl;}
protected:int _age;
};
void test3()
{Student s1("Tom", 18);Student s2("Mike", 20);s1 = s2;
}

4、析构

派生类对象会在析构时先析构自己的成员变量,再自动调用基类的析构函数去析构基类部分的成员变量,这样保证了先析构派生类再析构基类的顺序

在继承中,对于一个派生类对象:先构造其基类部分再构造派生类部分 ;先析构其派生类部分再析构基类部分

###代码示例:

class Person
{
public:Person(string name = "Peter"):_name(name){}~Person(){cout << "基类析构" << endl;}
protected:string _name;
};class Student :public Person
{
public:Student(string name = "Peter", int age = 19):Person(name), _age(age){}~Student(){cout << "派生类析构" << endl;}
protected:int _age;
};
void test3()
{Student s1("Tom", 18);Student s2("Mike", 20);
}

 二、实现一个无法被继承的类

  • 将这个类的构造函数的访问权限置为private,这样其他类想要继承时,无法调用基类的构造函数,那么派生类就无法实例化出对象,所以无法继承;
  • C++11新增关键字final,在类名后面加上一个final,表示最终类,含义是这个类无法被继承

1、

2、 


五、继承与友元

友元不能被继承,也就是说在基类中的友元函数不能访问派生类中的成员变量;

###代码示例:

class Student;
class Person
{friend void Print(const Person & p, const Student& s);
protected:string _name="Peter";
};
class Student :public Person
{
//friend void Print(const Person& p,const Student& s);
protected:int _age=19;
};
void Print(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._age << endl;
}
void test4()
{Person p1;Student s1;Print(p1,s1);
}

 想要在派生类里面也调用Print,则要把Print置为派生类的友元函数


六、继承与静态成员

被继承的静态成员是被派生类对象和基类公用的,静态成员只是受到类域的访问限定

###代码示例:

class Person
{
public:string _name="Peter";static int _count;
};
int Person::_count = 1;
class Student :public Person
{
protected:int _age = 19;
};
void test5()
{Person p1;Student s1;cout << &p1._name << endl;cout << &s1._name << endl;cout << &p1._count << endl;cout << &s1._count << endl;
}


七、多继承及菱形继承问题

单继承:一个派生类只有一个直接基类

多继承:派生类有两个或以上个基类的继承;

菱形继承是多继承的一种:

菱形继承会出现二义性和数据冗余的问题;

二义性:一个变量同时具有两个含义;

数据冗余:只需要一份的数据却存了多个;

###代码示例:

class Person
{
public:Person(const string name="Lois"):_name(name){}string _name;//姓名
};class Teacher:public Person
{
public:Teacher(string name="Tom_t",int id=101):Person(name),_id(id){}
protected:int _id;//职工编号
};class Student:public Person
{
public:Student(string name="Tom_s",int num=102):Person(name),_num(num){}
protected:int _num;//学号
};class Assistant:public Teacher,public Student
{
protected:string _majorCourse;
};
void test6()
{Assistant a1;//这样访问报错:_name 不明确//cout << a1._name << endl;//这样写可以明确_name,但是数据有冗余,也就是_name有多份,但是助手a1只有一个名字cout << a1.Student::_name << endl;cout << a1.Teacher::_name << endl;
}

1、虚继承

为了解决菱形继承的两个问题,这里使用虚继承,也就是在开始继承相同的基类的派生类后面加上virtual再加继承方式和基类; 

###代码示例:

class Teacher:virtual public Person
{
public:Teacher(string name="Tom_t",int id=101):Person(name),_id(id){}
protected:int _id;//职工编号
};class Student:virtual public Person
{
public:Student(string name="Tom_s",int num=102):Person(name),_num(num){}
protected:int _num;//学号
};
void test7()
{Assistant a1;a1._name = "Peter";cout << a1._name << endl;cout << a1.Student::_name << endl;cout << a1.Teacher::_name << endl;a1.Student::_name = "Mike";cout << a1._name << endl;cout << a1.Student::_name << endl;cout << a1.Teacher::_name << endl;
}

改成虚继承相当于_name是公用的了,只有一份;


八、继承与组合

  • public继承是一种 is-a 的关系,也就是说每个派生类对象都是基类对象;
  • 组合是一种has-a 的关系,例如B组合了A,那么每个B对象中都包含一个A对象;
  • 继承允许你根据基类的实现来定义派生类的实现,这种通过生成派生类的复用通常通常被称为白箱复用,白箱是相对于可视性而言;在继承方式中,基类内部细节对派生类可见。继承一定程度上破坏了派生类的封装,基类的改变,对于派生类有很大的影响。基类和派生类关系很强,耦合度高;
  • 对象组合是继承之外的另一种复用选择。新的更复杂的功能可以通过组合对象来获得,对象组合要求被组合的对象具有良好定义的接口。这种复用被称为黑箱复用,因为对象内部细节不可见。组合类之间没有很强的依赖关系,耦合度低。使用组合类对象有助于保持每个类被封装;
  • 两者据情况二用;
//继承
template<class T>
class stack :public vector<T>
{//······
};
//组合
template<class T>
class stack
{//······
private:vector<T> v;
};

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

帝佛卡干邑荣耀登陆泰国王权King Power

帝佛卡干邑与泰国王权免税集团&#xff08;King Power&#xff09;达成深度合作&#xff0c;共同将法国帝佛卡干邑品牌推向泰国旅游零售市场。此次合作不仅标志着帝佛卡干邑在国际市场的又一重要突破&#xff0c;也彰显了双方对高品质产品的共同追求。 帝佛卡干邑于2024年8月正…

[Python学习日记-53] Python 中的正则表达式模块 —— re

[Python学习日记-53] Python 中的正则表达式模块 —— re 简介 re 模块 练习 简介 我们在编程的时候经常会遇到想在一段文字当中找出电话号码、身份证号、身高、年龄之类的信息&#xff0c;就像下面的数据一样 # 文件名&#xff1a;美丽学姐联系方式.txt 姓名 地区 …

WinRAR技巧:如何独立压缩文件夹内的每个文件?

不知道大家是否会遇到这种情况&#xff0c;将文件夹内的多个文件或文件夹压缩成一个个压缩包文件&#xff0c;这种情况除了将文件夹中的文件一个个压缩&#xff0c;还有什么批量操作的方法呢&#xff1f;今天分享使用WinRAR批量压缩文件到每个单独的文件夹的方法。 方法如下&a…

pdf压缩如何操作?教你8招,轻松搞定文件压缩!

电脑上如果存有大量的pdf文件&#xff0c;那么一定会占用一定的空间&#xff0c;不仅不利于存储还影响传输速度。如果想要将pdf压缩变小&#xff0c;那么本文分享的内容可就要了解下了。 PDF文件怎么压缩变小&#xff1f;pdf压缩是一种常见的文件处理需求。无论是处理个人文档…

offset Explorer连接云服务上的kafka连接不上

以上配置后报连接错误时&#xff0c;可能是因为kafka的server.properties配置文件没配置好&#xff1a; 加上面两条配置&#xff0c;再次测试连接&#xff0c;成功 listeners和advertised.listeners

DICOM 基础知识:深入理解DICOM数据结构与标签说明

目录 DICOM 图像概念 DICOM 图像关键特性&#xff1a; DICOM 文件结构 常见数据元素&#xff1a; 数据元素示例详解 DICOM-VR 数据类型说明 DICOM 标准支持的数据集 结语 DICOM 图像概念 DICOM&#xff08;Digital Imaging and Communications in Medicine&…

ELK之路第二步——可视化界面Kibana

Kibana 1.安装2.解压3.修改配置4.启动 这部分内容就比较简单了&#xff0c;水一片文章。 1.安装 需要梯子 官网下载链接&#xff1a;https://www.elastic.co/cn/downloads/past-releases/kibana-7-3-0 如果你去官网下载页面&#xff0c;点击下载是404报错&#xff0c;记得切换…

UE5之5.4 第三人称示例代码阅读

第三人称的代码相对第一人称少了很多&#xff0c;只有一个移动跳跃的能力 构造函数&#xff0c;添加角色的移动属性&#xff0c;限制了当controller移动角色不会乱转&#xff0c;然后创建了一个相机杆&#xff0c;创建了一个跟随相机&#xff0c;绑到相机杆上 然后在这个函数设…

SpringMVC6-SpringMVC的视图

目录 ThymeleafView 转发视图 重定向视图 视图控制器view-controller SpringMVC中的视图是View接口&#xff0c;视图的作用&#xff1a;渲染数据&#xff0c;将模型Model中的数据展示给用户 SpringMVC视图的种类很多&#xff0c;默认有转发视图InternalResourceView 和重定…

基于Qt的多线程并行和循序运行实验Demo

致谢&#xff08;Acknowledgement&#xff09;&#xff1a; 感谢Youtube博主Qt With Ketan与KDAB精心录制的Qt多线程处理应用教程&#xff0c;感谢Bilibili博主爱编程的大丙对Qt多线程与线程池内容深入浅出的讲解。 一、计算机线程相关概念 线程概念[1]&#xff1a; 在计算机科…

【Anaconda】Anaconda3 下载与安装教程(Windows 11)

引言 Anaconda发行版是一个用于数据科学、机器学习和AI项目的平台。它包括数千个开源包&#xff0c;一个包和环境管理器&#xff0c;一个桌面应用程序&#xff0c;以及云服务。 安装步骤 下载安装程序 访问官方Anaconda网站下载安装程序。 https://www.anaconda.com/download/…

关闭windows更新方法

在windows更新里选择暂停windows更新 然后按下winr&#xff0c;输入regedit 在注册表里找到 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings\PauseUpdatesExpiryTime 修改时间即可

联想笔记本电脑睡眠后打开黑屏解决方法

下载联想机器睡眠无法唤醒修复工具 下载地址&#xff1a;https://tools.lenovo.com.cn/exeTools/detail/id/233/rid/6182522.html 使用完后重启电脑&#xff0c;问题解决。

多线程进阶——线程池的实现

什么是池化技术 池化技术是一种资源管理策略&#xff0c;它通过重复利用已存在的资源来减少资源的消耗&#xff0c;从而提高系统的性能和效率。在计算机编程中&#xff0c;池化技术通常用于管理线程、连接、数据库连接等资源。 我们会将可能使用的资源预先创建好&#xff0c;…

亿家旺生鲜云订单零售系统的设计与实现小程序ssm+论文源码调试讲解

2相关技术 2.1微信小程序 小程序是一种新的开放能力&#xff0c;开发者可以快速地开发一个小程序。小程序可以在微信内被便捷地获取和传播&#xff0c;同时具有出色的使用体验。尤其拥抱微信生态圈&#xff0c;让微信小程序更加的如虎添翼&#xff0c;发展迅猛。 2.2 MYSQL数据…

Vue笔记-element ui中关于table的前端分页

对于 Element UI 表格的前端分页&#xff0c;可以在组件中使用 JavaScript 来实现数据的分页显示&#xff0c;而不必从后端获取已分页的数据。以下是一个简单的示例&#xff0c;演示如何在前端进行 Element UI 表格的分页&#xff1a; <template><div><el-tabl…

SpringBoot核心框架之AOP详解

SpringBoot核心框架之AOP详解 一、AOP基础 1. AOP概述 AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程&#xff0c;面向方面编程&#xff09;&#xff0c;其实就是面向特定方法编程。 场景&#xff1a; 项目部分功能运行较慢&#xff0c;定位执行耗时…

CSS_定位_网页布局总结_元素的显示与隐藏

目录 目标 1. 定位 1.1 为什么需要定位 1.2 定位组成 1. 定位模式 2. 边偏移 1.3 静态定位 static&#xff08;了解&#xff09; 1.4 相对定位 relative&#xff08;重要&#xff09; 1.5 绝对定位 absolute&#xff08;重要&#xff09; 1.6 子绝父相的由来&#xff…

【CCL】浅析 CFX Command Language

【CCL】浅析 CFX Command Language 文章目录 【CCL】浅析 CFX Command LanguageI - 前言ActionsPower Syntax II - Perl 语法概述变量定义注释字符串操作符其他 CCL 语法概述参考链接 I - 前言 CCL 全称是 CFX Command Language &#xff0c;是 CFX-Post 软件内部通讯的命令行…

LLM | 论文精读 | NeurIPS 2023 | SWIFTSAGE: 结合快思考与慢思考的生成智能体

论文标题&#xff1a;SWIFTSAGE: A Generative Agent with Fast and Slow Thinking for Complex Interactive Tasks 作者&#xff1a;Bill Yuchen Lin, Yicheng Fu, Karina Yang, Faeze Brahman, Shiyu Huang, Chandra Bhagavatula, Prithviraj Ammanabrolu, Yejin Choi, Xian…