《C++ 继承》

目录

继承的定义

继承类模板

派生类和基类之前的转换

隐藏

派生类的默认成员函数

不能被继承的类

继承中的友元和静态成员

继承模型


继承的定义

继承的本质是一种复用。规定Person类为基类,Student类为派生类 。

继承方式分为public继承protected继承private继承。一般使用public继承,对成员的限制private > protected > public.

public继承,基类的private成员只能在基类使用,protected成员只能在基类和派生类中使用,public成员能在任意地方使用。

protect继承,基类的private成员只能在基类使用,protected成员只能在基类和派生类中使用,public成员只能在基类和派生类中使用。

private继承,基类的private成员只能在基类使用,protected成员只能在基类中使用,public成员只能在基类中使用。

//基类/父类
class Person
{
public://身份认证void identity(){cout << "void identity()" << endl;}void func(){_age++;}protected:string _name = "张三";string _address;string _tel;
private:int _age = 18;
};//子类/派生类
class Student : public Person
{
public://学习void study(){cout << "void study()" << endl;}//不能在派生类声明时直接在派生类中来改变基类的成员变量//_name = "李四";void Set_name(){_name = "李四";}
protected:int _stuid;//学号
};//不显示写继承方式 默认为private继承
//class Teacher : Person
class Teacher : public Person
{
public:void teach(){cout << "void teach()" << endl;//派生类中无法访问基类的private成员//age++;}protected:int _work_num;//工号};int main()
{Person p;p.identity();//基类调用成员函数Student s;s.identity();//派生类调用基类的成员函数Teacher t;t.identity();s.func();//调用基类的函数来改变基类的private变量s.Set_name();//调用成员函数可以该改变基类中的potected变量return 0;
}

继承类模板

在复用容器中的函数时会报错找不到标识符push_back()。

因为lzk::stack<int> s实例化了stack<int>和vector<int>,但是没有实例化vector<int>::push_back(x)。
这里的问题本质上时编译器对模板的两阶段查找规则
第一阶段(模板定义阶段)模板定义时自动触发(无需实例化)
            编译器会检查所有不依赖模板参数 T 的名称(即非依赖名称,如直接写的 push_back)。
            如果名称未在当前作用域或可见基类中声明,直接报错(即使基类模板实例化后可能有该成员)。

第二阶段(模板实例化阶段)实例化模板时触发(如 main() 中使用)
            检查所有依赖 T 的名称(如 vector<T>::push_back)。
            此时基类模板(如 vector<int>)已实例化,可以确认成员是否存在。

//基类为类模板
namespace lzk
{template<class T>class stack : public vector<T>{public:void push(const T& x){//报错找不到标识符//push_back();//lzk::stack<int> s;时实例化了stack<int> 和vector<int>//但是没有实例化vector<int>::push_back(x)//这里的问题本质上时编译器对模板的两阶段查找规则/*第一阶段(模板定义阶段)编译器会检查所有不依赖模板参数 T 的名称(即非依赖名称,如直接写的 push_back)。如果名称未在当前作用域或可见基类中声明,直接报错(即使基类模板实例化后可能有该成员)。这就是你遇到的 push_back 报错的根本原因。第二阶段(模板实例化阶段)检查所有依赖 T 的名称(如 vector<T>::push_back)。此时基类模板(如 vector<int>)已实例化,可以确认成员是否存在。*///阶段1:模板定义时自动触发(无需实例化)。//阶段2:实例化模板时触发(如 main() 中使用)。vector<int>::push_back(x);}void pop(){vector<int>::pop_back();}const T& top(){return vector<int>::back();}bool empty(){return vector<int>::empty();}};}int main()
{lzk::stack<int> s;s.push_back(1);s.push_back(2);s.push_back(3);s.push_back(4);while (!s.empty()){cout << s.top() << endl;s.pop();}return 0;
}

派生类和基类之前的转换

public继承的派生类对象可以赋值给基类的对象和指针和引用,但是基类对象不能赋值给派生类对象。 

//派生类对象和基类对象的转换
class Person
{
protected:string _name;string _sex;int _age;
};class Student : public Person
{
public:int _num;
};int main()
{Student s;//派生类对象可以赋值给基类的指针引用Person* p = &s;Person& rp = s;//派生类对象赋值给基类对象,通过基类的拷贝构造完成Person pojb = s;return 0;
}

隐藏

我们知道不同的类,有不同的类域,他们是相互独立的,如果基类和派生类中存在同名成员变量或同名成员函数,派生类成员将屏蔽基类对同名成员的直接访问,即隐藏。 

class Person
{
protected:string _name = "李四";string _sex = "男";int _age = 18;
public:void func(){cout << "func()" << endl;}
};class Student : public Person
{
public:void print(){//将基类中的_age隐藏了cout << _age << endl;}int _num = 22;int _age = 19;void func(int i){cout << "void func(int i)" << endl;}
};int main()
{Student s;s.print();//通过派生类对象调用基类隐藏函数,需要指定类域s.func(1);s.Person::func();return 0;
}

派生类的默认成员函数

构造函数的调用顺序是,先调用基类的构造函数,再调用派生类的构造函数;先析构派生类对象,再析构基类对象。 

如果显示调用基类的析构,有两个问题

1.在编译过后,编译器会将基类和派生类的析构函数名称改为destructor,那么基类和派生类的析构函数就会构成隐藏关系,则需要指定类域调用
2.调用过后发现基类析构了两次,编译器为了析构的顺序是先派生类再基类,会在调用派生类的析构后再调用基类析构,如果有动态资源就会报错。

//派生类的默认成员函数//基类
class Person
{
public:Person(const string& name = "张三"):_name(name){cout << "Person(const string& name = 张三)" << 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;_name = "";}
protected:string _name;};//派生类
class Student : public Person
{
public:Student(const string& n, int age, const string& name):Person(name), _n(n), _age(age){cout << "Student(const string& n, int age, const string& name)" << endl;}Student(const Student& s):Person(s)//显示调用基类的拷贝构造,_n(s._n),_age(s._age){cout << "Student(const Student& s)" << endl;}Student& operator=(const Student& s){cout << "Student& operator=(const Student& s)" << endl;if (this != &s){_n = s._n;_age = s._age;Person::operator=(s);//显示调用基类的赋值重载}return *this;}~Student(){//如果显示调用基类的析构,有两个问题//1.//在编译过后,编译器会将基类和派生类的析构函数名称改为destructor(涉及到多态)//那么基类和派生类的析构函数就会构成隐藏关系//则需要指定类域调用//2.//调用过后发现基类析构了两次//编译器为了析构的顺序是先派生类再基类 //会在调用派生类的析构后再调用基类析构    //如果有动态资源就会报错//Person::~Person();cout << "~student()" << endl;}
private:string _n = "李四";int _age = 19;};int main()
{Student s("李好", 19,"张斌");Student s1(s);//Student s3("李一", 18,"李二" );//s1 = s3;return 0;
}

不能被继承的类

实现一个不能被继承的类有两种方法

一是将基类的构造函数列为私有成员。

二是在基类的名字后面加final关键字。

//实现一个不能被继承的类
//c++11
class Base final//加关键字
{
public:	 void func5() { cout << "Base::func5" << endl; }
protected:int a = 1;
private://c++98 //将构造函数设为私有//Base()//{};
};
//报错
//class Student : public Base

继承中的友元和静态成员

友元关系不能被继承,基类的友元函数不能访问派生类的成员变量,除非给派生类也声明友元。

在基类中定义了静态成员,则在派生类中使用的也是这个成员,不会再开辟新的空间。

//继承和友元//前置声明
class Student;class Person
{
public:friend void print(const Person& p, const Student& s);
protected:int _age = 18;
};class Student : public Person
{
protected:string _name = "李思思";friend void print(const Person& p, const Student& s);
};void print(const Person& p, const Student& s)
{cout << p._age << endl;cout << s._name << endl;
}int main()
{Student s;Person p;print(p,s);return 0;
}//静态成员class Person
{
public:string _name;static int _count;
};//静态成员在类外定义
int Person::_count = 0;class Student : public Person
{
protected:int _stuNum;
};int main()
{Person p;Student s;//基类和派生类公用一个静态变量cout << &p._count << endl;cout << &s._count << endl;//基类和派生类非静态成员的地址是不一样的cout << &p._name << endl;cout << &s._name << endl;//通过指定类域可以访问静态成员cout << &Person::_count << endl;cout << &Student::_count << endl;return 0;
}

继承模型

单继承:一个派生类继承一个基类。

多继承:一个派生类继承多个基类。

菱形继承:诸如两个派生类继承同一个基类后,再被同一个派生类继承的情况。

菱形继承会产生数据冗余二义性的问题,为了解决这个问题就有了虚继承,虚继承就是在继承方式前面加上virtual关键字。那么派生类对象就可以访问基类公开成员了。

//单继承 多继承 菱形继承
class Person
{
public:string _name = "李思思";
};class Student : public Person
{
public:int _nun;
};class Teacher : public Person
{
public:int _worknum;
};class Assistant : public Student, public Teacher
{
protected:string _course; // 主修课程
};int main()
{//对_name的访问不明确//student类和teacher类中都有_nameAssistant a;//a._name = "lisisi";//指定类域可以访问,解决二义性问题,但是存在数据冗余a.Student::_name = "lisisi";a.Teacher::_name = "lss";
}//虚继承
//解决数据冗余和二义性class Person
{
public:string _name = "李思思";
};//加关键字virtaul
class Student : virtual public Person
{
public:int _nun;
};class Teacher : virtual public Person
{
public:int _worknum;
};class Assistant : public Student, public Teacher
{
protected:string _course; // 主修课程
};int main()
{Assistant a;a._name = "李思思";return 0;
}

任何足够先进的科技都与魔法无异,但魔法背后的真相永远是严谨的代码逻辑。愿我们既能享受创造的浪漫,也能保持对技术的敬畏之心 !🚀

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

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

相关文章

金蝶K3 ERP 跨网段访问服务器卡顿问题排查和解决方法

我一朋友公司反应&#xff0c;公司网络卡顿&#xff0c;测试掉包严重&#xff0c;抓包wireshark测试&#xff0c;发现arp包有大量mac欺骗&#xff0c;因为公司有几百台电脑&#xff0c;所以建议更换了三层交换机&#xff0c;划分了vlan&#xff0c;这样有效的避免了网络风暴等&…

无需安装!在线数据库工具 :实战 SQL 语句经典案例

在数字化时代&#xff0c;SQL&#xff08;结构化查询语言&#xff09;已成为数据从业者、开发人员乃至业务分析人员必备的核心技能。无论是处理日常数据报表&#xff0c;还是应对复杂的业务逻辑&#xff0c;SQL 都能高效实现数据的查询、操作与分析。本文将通过经典的 SQL 练习…

如何在网页里填写 PDF下拉框

对于PDF 开发者或网页开发者来说&#xff0c;让用户在网站上填写 PDF 下拉框&#xff08;Combo Box&#xff09;是一个棘手的问题。因为 PDF 并不是一种原生的 Web 格式&#xff0c;浏览器通常不允许用户与 PDF 下拉框进行交互。 那么&#xff0c;如何让用户在 HTML 中填写 PD…

.Net 优秀框架 ABP全面详解

文章目录 第一部分&#xff1a;ABP框架概述与核心架构1.1 ABP框架简介1.2 ABP框架架构解析1.2.1 表现层(Presentation Layer)1.2.2 分布式服务层(Distributed Service Layer)1.2.3 应用层(Application Layer)1.2.4 领域层(Domain Layer)1.2.5 基础设施层(Infrastructure Layer)…

力扣-198.打家劫舍

题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋…

windows 安装vllm cuda版本

windows 安装cuda版本 查看window cuda版本 nvidia-smi vllm 获取镜像,此版本需要cuda 版本12.8 或以上 docker pull vllm/vllm-openai:latest下载模型 git lfs installcd e:\ai mkdir vllm\models\qwen2cd vllm\models#通过git下载git clone https://www.modelscope.c…

Node.js特训专栏-基础篇:1. Node.js环境搭建与项目初始化详细指南

我将为你详细讲解 Node.js 环境搭建与项目初始化的步骤&#xff0c;包含常见问题解决和最佳实践&#xff0c;帮助你快速上手。 详细步骤说明 1. 环境搭建 Windows用户&#xff1a; 访问Node.js官网(https://nodejs.org)下载LTS版本安装包&#xff08;推荐长期支持版&#xf…

13.安卓逆向2-frida hook技术-HookJava构造方法

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取码&#xff1…

php基础:常见函数

内建函数 文章目录 内建函数1、文件操作函数&#xff1a;2、代码执行函数&#xff1a;3、反序列化函数&#xff1a;4、数据库操作函数&#xff1a;5、类型转换与比较函数&#xff1a;6、其他常见函数&#xff1a; 1、文件操作函数&#xff1a; include(): 导入并执行指定的 PHP…

教程:PyCharm 中搭建多级隔离的 Poetry 环境(从 Anaconda 到项目专属.venv)

核心思维&#xff1a;为什么需要 “多级隔离”&#xff1f; 在复杂项目中&#xff0c;环境冲突是最棘手的问题&#xff08;比如系统 Python 版本不同、依赖包版本冲突&#xff09;。通过 “Anaconda 虚拟环境 → 项目 Poetry 环境 → 工具级隔离” 的三层架构&#xff0c;实现…

Rollup vs Webpack 深度对比:前端构建工具终极指南

前端工程领域始终面临一个根本选择&#xff1a;如何在模块化编码规范与工程化构建效率之间取得最佳平衡。Rollup与Webpack分别代表着两种不同维度的解决方案&#xff0c;本文将揭示它们的真实应用场景与核心差异。 一、核心差异全景图&#xff08;附最新对比&#xff09; 核心能…

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…

Easy Excel

Easy Excel 一、依赖引入二、基本使用1. 定义实体类&#xff08;导入/导出共用&#xff09;2. 写 Excel3. 读 Excel 三、常用注解说明&#xff08;完整列表&#xff09;四、进阶&#xff1a;自定义转换器&#xff08;Converter&#xff09; 其它自定义转换器没生效 Easy Excel在…

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…

AI高考志愿助手应用架构设计并上线实施运行

环境: AI高考志愿助手 问题描述: AI高考志愿助手应用架构设计并上线实施运行 业务需求:开发一个AI升学助手,功能是帮助用户模拟填报高考志愿等功能,数据是历年各专业的录取分数线表格。数据确认: 近3年约100多万条数据,原始数据是excel表格数据。解决方案: 一、项…

深入浅出掌握 Axios(持续更新)

在了解ajax和axios之前&#xff0c;我们先观察一下他们是什么英文的缩写 ajax 的名字为 asynchroanous JavaScript and XML 而axios的名称来源于英文单词“axis”与“I/O”的结合&#xff0c;并非直接缩写自某个特定短语。 先导知识 在本文我们简单的介绍一下ajax后着重讲解…

windows10下搭建nfs服务器

windows10下搭建nfs服务器 有参考这篇博客 Windows10搭建NFS服务 - fuzidage - 博客园 下载 NFS Server这个app 通过网盘分享的文件&#xff1a;nfs1268 (1).exe 链接: https://pan.baidu.com/s/1rE4h710Uh-13kWGXvjkZzw 提取码: mwa4 --来自百度网盘超级会员v5的分享 下载后…

npm符号链接

前言 最近在写一个快应用项目&#xff0c;demo中依赖了本地文件&#xff0c;package.json如下&#xff1a; 此时 node_modules 下出现了 mysdk&#xff0c;复制整个项目&#xff0c;但是copy的项目中的node_modules并未出现该文件&#xff0c;导致报错。 解决方案 观察 pa…

SQL 中 IDENTITY 列的特殊处理.

SQL 处理中,遇到提示: "消息 544,级别 16,状态 1,第 3 行 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 BM 中的标识列插入显式值。" 即当 SQL Server 表中的 ​​标识列(Identity Column)​​ 插入显式值,但未启用 IDENTITY_INSERT 选项。由此报错,以下是详…

网络安全等级保护中关于SSL证书的整改如何处理?

SSL证书在网络安全等级保护&#xff08;等保&#xff09;体系中扮演着至关重要的角色&#xff0c;是实现多个等保核心要求&#xff08;尤其是三级及以上&#xff09;的关键技术手段之一。其重要性主要体现在以下几个方面&#xff1a; 满足“身份鉴别”要求&#xff08;等保要求…