认识C++继承

news2024/12/23 13:14:06

认识继承

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。

在这里插入图片描述

不写继承方式默认为私有private类型的
如果将类改为struct声明的则就会变为共有的public
继承类是不可访问父类的私有成员的,即使继承方式为共有的也不可以。访问的优先级是已最低的为主如图:

在这里插入图片描述

//继承
class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
	//protected:
private:
	string _name = "peter"; // 姓名
	int _age = 18;  // 年龄
};

//不写继承方式默认为私有private类型的
//如果将类改为struct声明的则就会变为共有的public

class Student :public Person
{
public:
	void func()
	{
		// 父类私有成员,子类用不了(无论什么方式继承)
		/*cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;*/
	}
protected:
	int _stuid; // 学号
};
class Teacher : public Person
{
protected:
	int _jobid; // 工号
};
int main()
{
	Student s;
	Teacher t;
	s.Print();
	//s.func();
	t.Print();

	return 0;
}

在这里插入图片描述

继承之间的关系

. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
保证派生类对象先清理派生类成员再清理基类成员的顺序。
5. 派生类对象初始化先调用基类构造再调派生类构造。
6. 派生类对象析构清理先调用派生类析构再调基类的析构。

子类对象和父类对象赋值问题

C++规定,当子类对象赋值给父类的时候,不会产生临时变量

#include <iostream>
#include <string>
using namespace std;
//继承
int main()
{
	Person p;
	Student s;

	//赋值兼容转换(切割,切片)
	p = s;
	return 0}

在进行赋值时,一般情况只允许子类赋值给父类(向上调整),如果需要父类赋值给子类时(向下调整),父类的定义需要时引用或者指针。

#include <iostream>
#include <string>
using namespace std;
//继承
class Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}

	//private:

	string _name = "peter"; // 姓名
	int _age = 18;  // 年龄
};

class Student :public Person
{
public:
	void func()
	{
		// 父类私有成员,子类用不了(无论什么方式继承)
		/*cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;*/
	}
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
protected:
	int _stuid; // 学号
};
class Teacher : public Person
{
protected:
	int _jobid; // 工号
};
int main()
{
	Person p;
	Student s;

	//赋值兼容转换(切割,切片)
	p = s;
	//向上取整
	//s = p;//报错;
	//向下取整,一般只有引用和指针类型才可以向下取整
	Person p1 = s;
	Person& rp = s;
	rp._name = "张三";

	Person* ptrp = &s;
	ptrp->_name = "李四";
	return 0;
}

在这里插入图片描述
赋值兼容转换(切割,切片)
在这里插入图片描述

继承的作用域

跟普通变量一样,C++也是遵守就近原则的,如果自己类里面没有才会找父类的。
如果想要用父类里的变量需要在调用变量前边加父类名字::

class Person
{
protected:
	string _name = "小李子"; // 姓名
	int _num = 111;
	// 身份证号
};
class Student : public Person
{
public:
	void Print()
	{
		cout << " 姓名:" << _name << endl;
		cout << " 子类数字:" << _num << endl;
		cout << " 父类数字:" << Person::_num << endl;
	}
protected:
	int _num = 999; // 学号
};

int main()
{
	Student s;
	s.Print();
	return 0;
}

在这里插入图片描述
通常我们称这种行为为隐藏或重定义:子类和父类有同名成员,子类的成员隐藏了父类的成员

继承的成员函数也会出现隐藏或者重定义现象,我们需要在调用的函数名前加父类名字::
如果函数名和父类的函数名一样就会构成重定义,不管有没有参数

class Person
{
public:
	void fun()
	{
		cout << "父类" << endl;
	}

protected:

	string _name = "小李子"; // 姓名
	int _num = 111;
	// 身份证号
};
class Student : public Person
{
public:

	void fun()
	{
		cout << "子类" << endl;
	}

	void Print()
	{
		cout << " 姓名:" << _name << endl;
		cout << " 子类数字:" << _num << endl;
		cout << " 父类数字:" << Person::_num << endl;
	}
protected:
	int _num = 999; // 学号
};

int main()
{
	Student s;
	s.Print();
	s.Person::fun();
	return 0;
}

在这里插入图片描述

子类和父类的成员函数关系

子类在初始化的时候,一定会调用父类的构造函数的。

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};

class Student : public Person
{
public:
	// 先父后子
	Student(const char* name = "张三", int id = 0)
		:_id(0)
	{}
protected:
	int _id;
};

int main()
{
	Student s1;
	return 0;
}

在这里插入图片描述

定义父类的成员时,我们可以直接通过子类来调用父类的匿名构造函数来进行初始化。

在这里插入图片描述
如果子类没有写父类成员的拷贝构造方法的话,会默认调用父类的构造方法

在这里插入图片描述
如果不想调用父类的默认构造方法的话需要自己实现

在这里插入图片描述
子类调用赋值操作的时候,如果子类里没有调用父类的赋值操作,也不会自动调用父类的,没有调用就是没有调用
在这里插入图片描述

子类父类析构问题

在这里插入图片描述

在这里插入图片描述

继承和友元

友元函数是不支持继承的,例如叔叔的朋友不是我的朋友,除非他成为我的朋友
在这里插入图片描述
在这里插入图片描述

继承静态成员之间的关系

静态成员属于父类和派生来
在派生类中不会单独拷贝一份,继承的是使用权

class Person
{
public:
    Person() { ++_count; }
public:
    string _name; // 姓名
public:
    static int _count; // 统计人的个数。
};
int Person::_count = 0;


class Student : public Person
{
protected:
    int _stuNum; // 学号 
};
int main()
{
    Person p;
    Student s1;
    Student s2;
    Student s3;
    cout << &s1._name << endl;
    cout << &p._name << endl;

    cout << &s1._count << endl;
    cout << &p._count << endl;

    cout << &Person::_count << endl;
    cout << &Student::_count << endl;

    cout << " 人数 :" << Person::_count << endl;
    cout << " 人数 :" << Student::_count << endl;
}

在这里插入图片描述
在这里插入图片描述

菱形继承及菱形虚拟继承

在这里插入图片描述

当这里的as进行调用时,由于继承的类都统一继承了另一个父类,导致共有变量age有两个,当我们访问时,就会出现以下报错

class Person
{
public:
	string _name;
	int _age;
};

class Student : public Person
{
protected:
	int _num;
};

class Teacher : public Person
{
protected:
	int _id;
};

class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse;
};

int main()
{
	Assistant as;
	as._age = 18;

	return 0;
}

在这里插入图片描述

解决方法一:

我们可以在变量名前面指定那个类的变量

在这里插入图片描述
这种方法只能解决眉下之急,所以也不是很实用,如果要彻底解决我们需要使用虚拟函数解决virtual

解决方法二:

**加粗样式
**

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

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

相关文章

Protobuf数据交互实战

"no one gonna make me down" 在之前呢&#xff0c;我们介绍了什么protobuf以及它的语法、数据类型。 一句老话说得好&#xff0c;"多说不练&#xff0c;假把式&#xff01;"。因此&#xff0c;本篇会选择以protobuf的语法&#xff0c;完成一个简易的通讯…

uniapp 微信小程序 自定义弹框+picker下拉选择列表+输入表单:拒绝-选择理由弹窗

效果&#xff1a; 1、template <!-- 拒绝-选择理由弹窗--> <view class"reason-popover" v-if"showReasonDialog"><view class"reason-modal"><view class"reason-title"><text>请选择拒绝理由<…

文心一言 VS 讯飞星火 VS chatgpt (64)-- 算法导论6.5 3题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;64&#xff09;-- 算法导论6.5 3题 三、要求用最小堆实现最小优先队列&#xff0c;请写出 HEAP-MINIMUM、HEAP-EXTRACT-MIN、HEAP DECREASE-KEY 和 MIN-HEAP-INSERT 的伪代码。 文心一言&#xff1a; 以下是使用最小堆实现最小…

界面控件DevExpress WPF数据编辑器组件,让数据处理更灵活!(二)

界面控件DevExpress WPF编辑器库可以帮助用户提供直观的用户体验&#xff0c;具有无与伦比的运行时选项和灵活性。WPF数据编辑器提供了全面的掩码和数据验证支持&#xff0c;可以独立使用&#xff0c;也可以作为容器控件(如DevExpress WPF Grid和WPF TreeList)中的单元格编辑器…

ubantu 安装 sudo apt install ubuntu-restricted-extras. 如何 OK

在安装的时候&#xff0c;不知道如何 Ok 使用 回车键&#xff0c;空格键 均不行&#xff0c;使用 Tab 键 &#xff0c;然后再使用 回车键。 Configuring ttf-mscorefonts-installer 答案是使用 Tab 键。

【Python】pyecharts 模块 ③ ( 使用 pyecharts 模块绘制折线图 )

文章目录 一、使用 pyecharts 模块绘制折线图1、折线图绘制过程2、完整代码示例 pyecharts 画廊网站 : https://gallery.pyecharts.org/#/ 在该网站可查看官方示例 一、使用 pyecharts 模块绘制折线图 1、折线图绘制过程 首先 , 导入 折线图 Line 对象 , 该类定义在 pyecharts…

Go http.Get不需要defer res.Body.Close()

前戏&#xff1a; go net/http包&#xff0c;必须要手动关闭嘛&#xff1f;非也。线上程序为啥协程数量直线上升&#xff0c;因为使用的姿势不对&#xff0c;请换个姿势。 干货&#xff1a; 手动关闭&#xff0c;释放资源 defer res.Body.Close() &#xff08;这是一个好习…

LeetCode[剑指Offer51]数组中的逆序对

难度&#xff1a;Hard 题目&#xff1a; 在数组中的两个数字&#xff0c;如果前面一个数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。输入一个数组&#xff0c;求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 限制&#xff1a; 0 < 数组…

C++【STL】queue和deque 容器详解

C【STL】queue和deque 容器详解 一级目录 二级目录 三级目录 1. 什么是queue容器&#xff1f; Queue是一种先讲先出( First In First Out,FIFO )的数据结构&#xff0c;它有两个出口。 queue模版类的定义在头文件中。 include 定义queue对象的示例代码如下∶ queue<i…

【华为c# OD机考参考答案】01---IPv4地址转换成整数

题目 1、题目 01---IPv4地址转换成整数2、解图思路 1、IP地址转为二进制 2、二进制转十进制 3、注意事项 1、IP地址的范围判断 2、空字符串判断 3、非法字符判断 4、考点 1、string的split 、convert等相关用法 2、正则表达式 3、进制转换 4、理解32位整数的意思 5、代码 判…

2023华为OD统一考试(B卷)题库清单(持续收录中)以及考点说明

目录 专栏导读2023 B卷 “新加题”&#xff08;100分值&#xff09;2023Q2 100分2023Q2 200分2023Q1 100分2023Q1 200分2022Q4 100分2022Q4 200分牛客练习题 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 刷的越多&…

【实用工具】-Git+GitLab

1. Git介绍 1.1 什么是Git&#xff1f; Git是一个分布式版本控制系统&#xff0c;用于跟踪和管理项目代码的变化。它是由Linus Torvalds于2005年创建的&#xff0c;旨在帮助开发者更好地协作、追踪代码的更改&#xff0c;并轻松地回滚到之前的版本。 Git相比传统的集中式版本…

网络安全 Day17-计算机网络知识02

计算机网络知识02 1. 交换机2. 网络知识名词3. ARP3.1 ARP通讯原理3.2 arp欺骗3.3 ARP欺骗与预防3.4 排查ARP病毒 4. 路由器 1. 交换机 什么是交换机 实现一个网络内多台主机之间通讯的设备用于电信号转发和放大的网络设备 常见的交换机&#xff1a;以太网交换机&#xff0c;电…

【Java】SpringBoot下写一个全局捕获异常的怎么实现?

文章目录 前言一、全局异常处理方式一1.1 自定义全局异常类1.2 手动抛出异常1.3 测试打印 二、全局异常处理方式二2.1 定义基础接口类2.2 定义枚举类2.3 自定义异常类2.4 自定义数据传输2.5 自定义全局异常处理2.6 测试代码 总结 前言 在日常项目开发中&#xff0c;异常是常见…

Nginx 用户指南:安装、配置和基本使用

前言 本用户指南将帮助您了解如何安装、配置和基本使用 Nginx。Nginx 是一款高性能的开源 Web 服务器和反向代理服务器&#xff0c;具有强大的性能和灵活性&#xff0c;可以满足各种 Web 服务器需求。 安装 Nginx a. 在 Ubuntu 上安装&#xff1a; $ sudo apt update $ sud…

(转载)神经网络遗传算法函数极值寻优(matlab实现)

本博客的完整代码获取&#xff1a; https://www.mathworks.com/academia/books/book106283.html 1案例背景 对于未知的非线性函数,仅通过函数的输入输出数据难以准确寻找函数极值。这类问题可以通过神经网络结合遗传算法求解,利用神经网络的非线性拟合能力和遗传算法的非线性…

【前端动画】科技感扫描效果 css动画animation

扫描出现动画 参考了网友写的二维码扫描 <template><div><div class"scan-content"><img style"width: 2rem;height: 2rem;" src"../../assets/images/eye.png" alt"" /><div class"line">…

四个现实中的商品样例,帮助你理解如何使用css【前端CSS入门样例】

实现商品列表 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>商品列表图片</title><style>.row > img {width: 15%;}</style></head><body><div class"row"><img sr…

【NOSQL】MongoDB

MongoDB MongoDB简介体系结构Linux系统中的安装启动和连接&#xff08;1&#xff09;先到官网下载压缩包——>解压——>重命名新建几个目录&#xff0c;分别用来存储数据和日志&#xff1a;新建并修改配置文件官网下载MongoDB Compass MongoDB简介 MongoDB是一个开源、高…

从零开始学习 Java:简单易懂的入门指南(二)

Java基础语法 1. 注释1.1使用的技巧1.2注意点 2. 关键字2.1 概念2.2 第一个关键字class 3. 字面量3.1区分技巧 4. 变量4.1 什么是变量&#xff1f;4.2 变量的定义格式4.2.1 格式详解4.2.2 常用的数据类型4.2.3 变量的注意事项 4.3 变量的练习 5. 数据类型5.1 Java语言数据类型的…