【C++】继承(inheritance)

引入

假设我们有一个动物类

class Animal {
public:
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};

又想写一个狗类,它也有年龄,也会吃,除此之外还有种类

class Dog {
public:
    const char* kind;
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};

我们发现有重复的代码,如果我们写猫类、鸟类等都要再写一遍,这样很麻烦

那么有没有一种方法能提高代码的复用性,不需要再写一遍就能达到同样的效果呢?

我们让Dog继承Animal

#include<iostream>
class Animal {
public:
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};
class Dog :public Animal {
public:
    const char* kind;
};
int main() {
    Dog dog;
    dog.kind = "柯基";
    dog.age = 3;
    dog.eat();
}

没有写那部分重复代码却也能给age赋值,调用eat()方法

也就是说,Dog继承了Animal,Animal所拥有的age和eat()它也就有了,就像父亲遗传给儿子一样

  • Animal就叫做父类或者基类
  • Dog就叫做子类或者派生类

而且,狗本来就属于动物,我们让其继承动物也是符合思维的

单继承和多继承

class A {
};
class B :public A {//单继承
};
class D {
};
class E {
};
class F :public D, public E {//多继承
};

那么,子类继承父类后,父类的所有内容都能被子类访问吗?

继承方式

我们看到上面的继承有"public",这其实是继承方式

继承方式就是类中的三种访问属性,每种访问属性通过继承方式之后在派生类中可能会有新的属性

  1. 基类私有成员,不管用什么方式继承,都不能被访问
  2. 其他的成员访问属性和继承方式,两者看谁更严格就按严格的来:public<protected<private
基类成员的访问控制public继承protected继承private继承
private可以继承,但不可以访问可以继承,但不可以访问可以继承,但不可以访问
protectedprotectedprotectedprivate
publicpublicprotectedprivate

派生类的构成

  1. 派生类会继承除基类的构造析构函数之外的所有成员变量和成员函数
  2. 可以在派生类中添加新的成员,通过派生类对象来调用
  3. 如果派生类中添加的成员名和基类成员名相同,那么派生类会隐藏基类的成员,可以通过.基类名::基类成员名来访问。如果是继承的多个基类,而多个基类中也有同名的,也是通过此种方式调用同名的成员。子类对象直接访问同名成员,访问的是子类对象自己的同名成员。

示例:

#include<iostream>
class Animal {
public:
    int age;
    void eat() {
        std::cout << "吃东西!" << std::endl;
    }
};
class Dog :public Animal {
public:
    const char* kind;
    void eat() {
        std::cout << "啃骨头!" << std::endl;
    }
};
int main() {
    Dog dog;
    dog.eat();
    dog.Animal::eat();
}

派生类和基类的关系

子类不包含父类,而是子类中有父类的所有数据成员和函数成员(除构造析构)。派生类是基类对象,但是基类不是派生类对象;派生类可以赋值给基类,而基类不能给派生类赋值。

派生类的构造析构顺序

  1. 派生类对象在实例化的时候是会调用基类的构造函数的,先基类后派生类(先有父亲后有儿子),释放就是先儿子后父亲,因为栈结构(先进后出)
  2. 如果是多继承,其与单继承中构造顺序一致;区别在于,在构造基类时有多个基类,那么会按照基类的继承声明顺序来依次调用基类的构造函数,然后构造子对象,最后构造自己
  3. 在写继承的时候,要确保基类有可以调用的构造函数
  4. 带参构造:在构造过程中,如果基类或子对象需要参数来进行构造,就需要通过成员初始化列表来构造

示例1:

#include<iostream>
class A {
public:
	A() {
		std::cout << "调用A的无参构造" << std::endl;
	}
	A(int a) {
		std::cout << "调用A的有参构造" << std::endl;
	}
	~A() {
		std::cout << "调用A的析构" << std::endl;
	}
};
class B :public A {
public:
	B() {
		std::cout << "调用B的无参构造" << std::endl;
	}
	B(int b) {
		std::cout << "调用B的有参构造" << std::endl;
	}
	~B() {
		std::cout << "调用B的析构" << std::endl;
	}
};
int main() {
	B b1;
	B b2(5);
}

运行结果:

调用A的无参构造
调用B的无参构造
调用A的无参构造
调用B的有参构造
调用B的析构
调用A的析构
调用B的析构
调用A的析构

示例2:

#include<iostream>
class A {
public:
	A(int a) {
		std::cout << a << std::endl;
	}
};
class B :public A {
public:
	B():A(1){}//在初始化列表中调用父类的带参构造
	//不这样写直接实例化会报错
};
int main() {
	B b1;
}

派生类的内存大小

  • 派生类的内存大小=所有父类内存大小之和+本身新增的成员内存大小
  • 派生类的内存中,基类的内存在最低位,派生类的内存在最高位

菱形继承

菱形继承

类B,C分别继承A;类D继承类B,C

这样继承会导致类D继承两份类A的成员,在类D对象,想要访问类A的成员的时候,会导致访问不明确。因为类B,C各自继承类A的成员

解决方法

(1)通过类名::成员名来确定调用哪个成员(不常用)

(2)通过虚继承,在继承方式的前面加上关键字virtual,虚继承之后会使在虚继承的类中多个指针(内存就会变大),但是在最后的D类,不会再继承两份A的成员了

示例1:

#include<iostream>
class A {
	int a = 1;
};
class B :public A {
	int c = 2;
};
class C :public A {
	int d = 3;
};
class D :public B, public C {
	int e = 4;
};
int main() {
	std::cout << sizeof(A) << std::endl;//4
	std::cout << sizeof(B) << std::endl;//8
	std::cout << sizeof(C) << std::endl;//8
	std::cout << sizeof(D) << std::endl;//20
}

示例2:

#include<iostream>
class A {
	int a = 1;
};
class B :virtual public A {
	int c = 2;
};
class C :virtual public A {
	int d = 3;
};
class D :public B, public C {
	int e = 4;
};
int main() {
	std::cout << sizeof(A) << std::endl;//32位:4	64位:4
	std::cout << sizeof(B) << std::endl;//32位:12	64位:24
	std::cout << sizeof(C) << std::endl;//32位:12	64位:24
	std::cout << sizeof(D) << std::endl;//32位:24	64位:48
}

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

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

相关文章

ThinkPad t61p 作SMB服务器,打印服务器,pc ,android ,ipad利用此服务器互传文件

1.在t61p上安装win7 2,配置好smb 服务 3.再安装好打印驱动程序 4.pc与win7利用系统的网络互相发现,映射为硬盘使用。 5.android&#xff0c;ipad安装ES文件浏览器访问win7 共享文件夹&#xff0c;互传文件。 6.android手机安装FE文件浏览器&#xff0c;可以利用花生壳外网…

Vue.js基础——贼简单易懂!!(响应式 ref 和 reactive、v-on、v-show 和 v-if、v-for、v-bind)

Vue.js是一个渐进式JavaScript框架&#xff0c;用于构建用户界面。它专门设计用于Web应用程序&#xff0c;并专注于视图层。Vue允许开发人员创建可重用的组件&#xff0c;并轻松管理状态和数据绑定。它还提供了一个虚拟DOM系统&#xff0c;用于高效地渲染和重新渲染组件。Vue以…

Hive基础面试-如何理解复用率的

1. 模型的复用率你们是怎么做的&#xff1f; 简单直白的说就是你的模型复用率如何&#xff0c;在业务方是否认可该模型&#xff0c;也是衡量模型建设的一个标准&#xff0c;复用率数&#xff1a;数仓模型涉及的核心是追求模型的复用和共享&#xff0c;引用系数越高&#xff0c;…

Excel - VLOOKUP函数将指定列替换为字典值

背景&#xff1a;在根据各种复杂的口径导出报表数据时&#xff0c;因为关联的表较多、数据量较大&#xff0c;一行数据往往会存在三个以上的字典数据。 为了保证导出数据的效率&#xff0c;博主选择了导出字典code值后&#xff0c;在Excel中处理匹配字典值。在查询百度之后&am…

鸿蒙学习笔记:初探UI开发

介绍了ArkUI相关内容&#xff0c;涵盖其基本概念&#xff0c;如组件、页面及二者作用。阐述了ArkUI主要特征&#xff0c;包括多态组件、多样布局等多方面能力。还讲解了声明式、类Web两种开发范式及适用场景。声明式开发范式从多维度提供UI能力&#xff0c;介绍了其基础能力、整…

OceanBase Shell开放内核运维接口,运维更便捷

DBA在日常业务中面临着繁琐的运维管理任务&#xff0c;亟需高效的工具和灵活的解决方案帮助他们简化操作、提升效率。因此&#xff0c;命令行操作和维护工具&#xff08;CLI工具&#xff09;&#xff0c;因其高效、灵活、可远程管理以及技术深度等特点&#xff0c;成为DBA和开发…

springboot配置https,并使用wss

学习链接 springboot如何将http转https 可借鉴的参考&#xff1a; springboot如何配置ssl支持httpsSpringBoot配置HTTPS及开发调试的操作方法springboot实现的https单向认证和双向认证(java生成证书)SpringBoot配置Https访问的详细步骤SpringBoot配置Https入门实践springboo…

高精度计算题目合集

高精度计算题目合集 1168&#xff1a;大整数加法 1168&#xff1a;大整数加法 1168&#xff1a;大整数加法 高精度加法原理&#xff1a; a&#xff0c;b&#xff0c;c 都可以用数组表示。这些都是基于c语言的算术运算符形成的运算。 c 3 ( c 1 c 2 ) % 10 c_3(c_1c_2)\%1…

Javaweb前端HTML css 整体布局

最后一个是线条颜色 盒子&#xff0c;整体还是300&#xff0c;400

测试人员--如何区分前端BUG和后端BUG

在软件测试中&#xff0c;发现一个BUG并不算难&#xff0c;但准确定位它的来源却常常让测试人员头疼。是前端页面的问题&#xff1f;还是后台服务的异常&#xff1f;如果搞错了方向&#xff0c;开发人员之间的沟通效率会大大降低&#xff0c;甚至导致问题久拖不决。 那么&#…

嵌入式:Flash的分类以及Jlink/J-flash的编程支持

相关阅读 嵌入式https://blog.csdn.net/weixin_45791458/category_12768532.html?spm1001.2014.3001.5482 常见的Flash大致可以分为以下大类&#xff1a; Serial Nor FlashSerial Nand FlashParallel Nor FlashParallel Nand FlashSerial EEPROM Serial Nor Flash 介绍 Se…

【Linux系统编程】第五十弹---构建高效单例模式线程池、详解线程安全与可重入性、解析死锁与避免策略,以及STL与智能指针的线程安全性探究

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、将日志加到线程池 1.1、Thread类 1.2、ThreadPool类 1.2.1、HandlerTask() 1.2.2、其他公有成员函数 1.3、主函数 2、…

基于SSM的作业批改系统+LW示例参考

1.项目介绍 功能模块&#xff1a;管理员&#xff08;学生管理、教师管理、作业信息管理、作业提交管理、作业批改管理等&#xff09;、学生&#xff08;个人信息管理、作业提交、作业查看等&#xff09;、教师&#xff08;个人中心、作业创建、作业批改等&#xff09;技术选型…

RabbitMQ高可用延迟消息惰性队列

目录 生产者确认 消息持久化 消费者确认 TTL延迟队列 TTL延迟消息 惰性队列 生产者确认 生产者确认就是&#xff1a;发送消息的人&#xff0c;要确保消息发送给了消息队列&#xff0c;分别是确保到了交换机&#xff0c;确保到了消息队列这两步。 1、在发送消息服务的ap…

嵌入式面试八股文(十)·RS485特性分析、CAN硬件同步和再同步遵从规则、SPI四种工作模式、错误帧基本概念

目录 1. 相较于传统的RS232接口&#xff0c;RS485的接口特性有哪些&#xff1f; 2. 在CAN接口协议中硬件同步和再同步需要遵从哪些规则&#xff1f; 3. 为什么位错误不能用于帧间隔&#xff1f; 4. SPI四种工作模式&#xff1f; 5. 关于错误帧&#xff0c;基本概念&a…

librdns一个开源DNS解析库

原文地址&#xff1a;librdns一个开源DNS解析库 – 无敌牛 欢迎参观我的个人博客&#xff1a;无敌牛 – 技术/著作/典籍/分享等 介绍 librdns是一个开源的异步多功能插件式的解析器&#xff0c;用于DNS解析。 源代码地址&#xff1a;GitHub - vstakhov/librdns: Asynchrono…

cookie反爬----普通服务器,阿里系

目录 一.常见COOKIE反爬 普通&#xff1a; 1. 简介 2. 加密原理 二.实战案例 1. 服务器响应cookie信息 1. 逆向目标 2. 逆向分析 2. 阿里系cookie逆向 1. 逆向目标 2. 逆向分析 实战&#xff1a; 无限debugger原理 1. Function("debugger").call() 2. …

大数据新视界 -- 大数据大厂之 Impala 性能优化:跨数据中心环境下的挑战与对策(上)(27 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

width设置100vh但出现横向滚动条的问题

在去做flex左右固定,中间自适应宽度的布局时, 发现这样一个问题: 就是我明明是宽度占据整个视口, 但是却多出了横向的滚动条 效果是这样的 把width改成100%,就没有滚动条了 原因: body是有默认样式的, 会有一定的默认边距, 把默认边距清除就是正常的了 同时, 如果把高度设…

百度在下一盘大棋

这两天世界互联网大会在乌镇又召开了。 我看到一条新闻&#xff0c;今年世界互联网大会乌镇峰会发布“2024 年度中国互联网企业创新发展十大典型案例”&#xff0c;百度文心智能体平台入选。 这个智能体平台我最近也有所关注&#xff0c;接下来我就来讲讲它。 百度在下一盘大棋…