继承初级入门复习

注意:保护和私有在类中没有区别,但是在继承中有区别,private在继承的子类不可见,protect在继承的子类可见 

记忆方法:先看基类的修饰符是private,那都是不可见的。如果不是,那就用继承的修饰和基类的修饰比较谁小取谁----->public>protect>private

#include <iostream>
using namespace std;
class Person
{
protected:
	string _name;
	string _sex;
	int _age;
};
class Student :public Person
{
public:
	int _No;
};
int main()
{
	Person p;
	Student s;

	//子类和父类之间赋值兼容规则
	//1、子类对象可以赋值父类对象/指针/引用
	p = s;
	Person* p1 = &s;
	Person& p1 =  s;
	return 0;
}

注意:父类不可以赋值给子类,有一种情况就是父类指向子类,再赋值给另一个子类

不同作用域(隐藏(重定义))

class Person
{
protected:
	string _sex;
	int _age=111;
};
class Student :public Person
{
public:
	void f()
	{
		cout << _age << endl;
	}
public:
	int _age=99;
};
int main()
{
	Student s;
	s.f();
}

面向对象的三大特性

封装(类的封装)、继承、多态

实际上面向对象不只三大特性

派生类的默认成员函数

注意:如果是自定义类型就会调用自己的默认构造函数(struct  class)

如何在子类中初始化父类部分呢?

class Person
{
public:
	Person(const char* name)
		:_name(name)
	{

		cout << "Person()" << _name<< endl;
	}
	~Person()
	{
		cout << "~Person()" << endl;
	}
private:
	string _name;
};
class Student : public Person
{
public:
	Student(const char* name,int age)//所以要加const这个块空间是只读
		:Person(name),
		_stuid(age)

	{

	}
protected:
	int _stuid;
};
int main()
{
	Student a("joker",1);//传入常量字符串
	return 0;
}

父类继承部分一定要调用父类去完成,如果不显示调用的话也会自动调用父类的构造函数

假设1:

默认构造函数包括无参、全缺省、系统默认生成的

如果是系统调用的默认构造函数内置类型是不会处理的,只有自定义类型才会处理

假设2:

如何完成子类拷贝构造呢?

什么是拷贝构造?

1、拷贝构造的参数只有一个,该参数的类型是对象类型的引用,为什么要引用?因为防止无限的调用拷贝构造去递归,一般用const修饰

2、要区分深拷贝和浅拷贝的问题,系统默认生成的拷贝函数的内存存储方式是字节序存储所以要注意成员变量类型的,防止释放两次同一个空间

复习完成

class Person
{
public:
	Person(const char*name="")
		:_name(name)
	{
		cout <<_name << "Person()" << endl;
	}
	Person(const Person& p1)
		:_name(p1._name)
	{
		cout << "Person(const Person& p1)" << endl;
	}
private:
	string _name;
};
class Student :Person
{
public:
	Student(const char*name,int id)
		:Person(name),//要以父类名()的方式调用父类构造函数初始化子类中的父类部分
		_stuid(id)
	{
		cout << "student()" << endl;
	}
	Student(const Student& s1)
		:Person(s1)//要以父类名()的方式调用父类的拷贝构造函数  复制子类中的父类部分
	{
		_stuid = s1._stuid;
		cout << "Student(const Student& s1)" << endl;
	}
private:
	int _stuid;
};

int main()
{
	//Person p1("aaa");
	Student s1("bbb",9);//初始化
	Student s2(s1);//拷贝构造
	//Student s3 ("gg",30);//初始化
	//s1 = s3;//s1.operator=(s3)

	return 0;
}

注意:只有显示的用父类(子类对象)的显示调用方式才可以调用父类的拷贝构造,系统不会自动调用父类的拷贝构造这个和初始化构造不一样

子类的operator=:

class Person
{
public:
//初始化
	Person(const char*name="")
		:_name(name)
	{
		cout <<_name << "Person()" << endl;
	}
//拷贝
	Person(const Person& p1)
		:_name(p1._name)
	{
		cout << "Person(const Person& p1)" << endl;
	}
//父类的operator=函数
	Person& operator=(const Person& s1)
	{
		if (this != &s1)
		{
			_name = s1._name;
			cout << "Person& operator=(const Person& s1)" << endl;
		}
		return *this;
	}
private:
	string _name;//string(const char*s1)
};
class Student :Person
{
public:
	Student(const char*name,int id)
		:Person(name),
		_stuid(id)
	{
		cout << "student()" << endl;
	}
	Student(const Student& s1)
		:Person(s1)//要以父类名()的方式调用父类的拷贝初始化子类中的父类部分
	{
		_stuid = s1._stuid;
		cout << "Student(const Student& s1)" << endl;
	}
//operator=
	Student& operator=(const Student& s1)
	{
		if (this != &s1)//防止赋值时,两个对象时一个对象,浪费时间
		{
			Person::operator=(s1);//显示调用父类的operator=,将父类的部分赋值
			_stuid = s1._stuid;
			cout << "Student& operator=(const Student& s1)" << endl;
		}
		return *this;//返回子类的对象
	}
private:
	int _stuid;
};

int main()
{
	//Person p1("aaa");
	Student s1("bbb",9);//初始化
	Student s2(s1);//拷贝构造
	//Student s3 ("gg",30);//初始化
	//s1 = s3;//s1.operator=(s3)

	return 0;
}

子类的析构函数 

注意:

1、子类的初始化时先父后子,所以析构就是先子后父,类似于stack

2、虽然父类的析构和子类的析构名字不相同,但是子类和父类的析构会被统一的处理成destructor构成隐藏

3、系统已经实现好当子类析构完成了,就会自动调用父类的析构

面试题

如何构建一个不可以继承的类

#include <iostream>
using namespace std;

class A
{
private:   //将父类的初始化私有化
   A()
   {
   }
}
class B:public A
{
  
}
int main()
{
   B b;//初始化不了对象
   return 0;
}

 友元关系不能被继承(了解就好)

会报错,要是想用只可以手动添加

静态成员在父类中被继承会发生什么?


class Person
{
public:
	Person()
	{
		_count++;
	}

public:
	string _name;
	static int _count;
};

int Person::_count = 0;//静态成员必须初始化

class Student:public Person
{
public:
private:
	int id;
};

int main()
{
	Person p1;
	Student s1; 
	p1._name = "jack";
	s1._name = "rose";
	p1._count = 1;
	s1._count = 2;
	cout << Person::_count << endl;//静态成员属于对象也属于类所以可以Person::_count
	return 0;
}

static 成员属于对象也是属于类的,子类继承下来的静态成员和父类是一样的它们调用同一个静态成员变量

多继承

什么叫单继承:只有一个父类

所以多继承:就是有多个父类

多继承会造成很多问题的,所以后来的语言是没有多继承的,多继承是一个大坑

为什么是大坑?

因为多继承的一种特殊的继承菱形继承,会造成数据冗余和二义性

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";//菱形继承会导致二义性不知道是那个的_name
	// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";
}

菱形继承:

菱形继承原理

experiment:

class A
{
public:
	int _a;
};
class B:public A
{
public:
	int _b;
};
class C :public A
{
public:
	int _c;
};
class D:public B , public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

进入调试看内存

这是内存模型,存在数据冗余和二义性

但是我们要看虚继承的内存模型

using namespace std;
class A
{
public:
	int _a;
};
class B:virtual public A//添加了virtual
{
public:
	int _b;
};
class C :virtual public A
{
public:
	int _c;
};
class D:public B , public C
{
public:
	int _d;
};
int main()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	return 0;
}

进入调试内存

接下来看看这些是什么?

好像是地址

再次进入内存

存在偏移量,存放偏移量的地方又叫虚基表

为什么要设计出来呢?

因为菱形继承会出现数据冗余和二义性,所以virtual继承是为了解决二义性和数据冗余

菱形继承:

虚继承:

为什么虚继承会比菱形继承还大呢?

是因为多了两个指针 

我相信很多同学会问不是解决数据冗余吗?为什么越来越大了

因为基类太小了

菱形继承:

虚继承:

少了一倍

这就是虚继承的基本概念

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

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

相关文章

知了传课Flask学习(持续更新)

一、基础内容 1.Flask快速应用 pip install flask from flask import Flaskapp Flask(__name__)app.route(/) def index():return Hello worldif __name__ __main__:app.run() 2.debug、host、port配置 from flask import Flask,requestapp Flask(__name__)app.route(/) d…

在洁净实验室设计装修中怎么选择合适实验室家具?

在现代科学研究和技术开发中&#xff0c;洁净实验室装修设计成为了确保实验准确性和安全性的重要因素。洁净实验室需要提供一个无尘、无菌、受控的环境&#xff0c;而在洁净实验室装修设计这个过程中&#xff0c;如何选择合适的实验室家具就显得尤为重要&#xff0c;因为它直接…

第一行代码 按书配置Menu不出来

问题&#xff1a;按照书本配置Menu&#xff0c;就是不出来 页面activity 源码 重写了&#xff1a;onCreateOptionsMenu(), onOptionsItemSelected() package com.example.lanidemoktimport android.os.Bundle import android.util.Log import android.view.Menu import andro…

欢乐钓鱼大师攻略大全,游戏自动辅助,钓鱼大全!

欢迎来到《欢乐钓鱼大师》的攻略大全&#xff01;本文将为你详细介绍游戏中的各类玩法、技巧和注意事项&#xff0c;帮助你快速掌握游戏精髓&#xff0c;成为一名真正的钓鱼大师。攻略内容包括新手鱼竿选择、锦标赛攻略、实用技巧、藏宝图玩法、箱子开法等多个方面。让我们一起…

个人博客网站开发笔记3

文章目录 前言p4 Front Matterp5 配置文件p6 命令p7 部署新的教学视频部署博客到github找视频教程也是一个技能详细步骤安装主题安装渲染器修改主题创建gitub仓库生成密钥验证密钥是否匹配修改config文件推送到github 前言 主要是安装啥的比较费劲 现在已经比较简单了感觉 之…

面试问题小结

说说你的项目&#xff0c;从里面学到啥了&#xff08;随便说&#xff09; CAS 线程池 的各个方面 线程咋创建&#xff08;4种方式&#xff09; 说一下聚集索引和非聚集索引 50w男 50w女 &#xff0c;在B树中咋存储的&#xff08;类似下面的图&#xff0c;变通一下就行了&a…

WXML模板语法-事件绑定

一、 1.事件 事件是渲染层到逻辑层的通讯方式&#xff0c;通过事件可以将用户在渲染层产生的行为&#xff0c;反馈到逻辑层进行业务的处理 2.小程序中常用的事件 3.事件对象的属性列表 当事件回调触发的时候&#xff0c;会收到一个事件对象event&#xff0c;其属性为&#x…

一文带你入门ini格式

引入: 以蜂鸣器为例&#xff0c;每次我们增加新的设备&#xff0c; 都需要添加两个新文件: 修改程序代码&#xff0c;手动添加: 缺点: 不利于维护 设备类节点直接通过ini文件配置 什么是.ini文件 ini文件通常以纯文本形式存在&#xff0c;并且包含了一个或多个节&#xff08;se…

快速搭建流媒体服务

1、安装流媒体服务 源码地址&#xff1a;https://gitee.com/ossrs/srs 本次采用docker安装 docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080 -p 8000:8000/udp -p 10080:10080/udp registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5 查看运行效果&#xff…

[LLM-Agents]浅析Agent工具使用框架:MM-ReAct

上文LLM-Agents]详解Agent中工具使用Workflow提到MM-ReAct框架&#xff0c;通过结合ChatGPT 与视觉专家模型来解决复杂的视觉理解任务的框架。通过设计文本提示&#xff08;prompt design&#xff09;&#xff0c;使得语言模型能够接受、关联和处理多模态信息&#xff0c;如图像…

QQ技术导航源码附带交易系统

网站功能 QQ登录 友联自助交换 友情链接交易功能 多功能搜索 ico小图标本地化 网站图片本地化 蜘蛛日志 文章评论 网站评论 自助链接匿名提交站点&#xff0c;添加友链访问网站自动审核通过 VIP 会员等级 VIP 付费升级 单个文章或者站点付费快审 多背景图片可自定义背景图片…

【数据结构】第七节:堆

个人主页&#xff1a; 深情秋刀鱼-CSDN博客 数据结构专栏&#xff1a;数据结构与算法 源码获取&#xff1a;数据结构: 上传我写的关于数据结构的代码 (gitee.com) ​ 目录 一、堆 1.堆的概念 2.堆的定义 二、堆的实现 1.初始化和销毁 2.插入 向上调整算法 3.删除 向下调整算法…

9.STL中list的常见操作(图文并茂)

目录 1.list的介绍及使用 1.1.list的构造 1.2 list iterator的使用 1.3. list capacity 1.4.list modifiers 1.5.list的迭代器失效 1.list的介绍及使用 list介绍 &#xff0c;可以通过以下图直观的感受到 vector 和 list 的区别 Vector 插入代价高&#xff0c;但便于排…

LabVIEW与串口通讯在运行一段时间后出现数据接收中断的问题

这些问题可能与硬件、软件或通信协议有关。以下是详细的原因分析和可能的解决方案&#xff1a; 一、硬件原因 串口线缆或接口问题&#xff1a; 由于长时间使用&#xff0c;串口线缆可能出现接触不良或损坏。接口松动也可能导致通讯中断。 解决方案&#xff1a;检查并更换串口…

【区块链】智能合约漏洞测试

打开Ganache vscode打开智能合约漏洞工程 合约内容 pragma solidity >0.8.3;contract EtherStore {mapping(address > uint) public balances;function deposit() public payable {balances[msg.sender] msg.value;emit Balance(balances[msg.sender]);}function with…

完成商品属性分组和商品属性关联维护

文章目录 1.前端页面搭建1.复制attrgroup-attr-relation.vue到src/views/modules/commodity下2.加入超链接和引入组件 src/views/modules/commodity/attrgroup.vue1.加入超链接2.引入组件 3.数据池加入变量4.使用组件1.引用组件2.添加方法3.测试&#xff0c;点击关联&#xff0…

【笔记】Qt 按钮控件介绍(QPushButton,QCheckBox,QToolButton)

文章目录 QAbstractButton 抽象类(父类)QAbstractButton 类中的属性QAbstractButton 类中的函数QAbstractButton 类中的信号QAbstractButton 类中的槽 QPushButton 类(标准按钮)QPushButton 类中的属性QPushButton 类中的函数、槽 QCheckBox 类(复选按钮)QCheckBox 类的属性QCh…

【全部更新完毕】2024电工杯A题数学建模详细思路代码文章分享

A 题&#xff1a;园区微电网风光储协调优化配置 摘要 在全球范围内&#xff0c;气候变化和环境污染问题日益严重&#xff0c;减少碳排放和实现可持续发展成为各国的共同目标。新能源&#xff0c;尤其是风能和光伏发电&#xff0c;因其清洁、可再生的特性&#xff0c;正在全球范…

国产化服务器设计 原理图:905-多路PCIe的阵列计算全国产化服务器

多路PCIe的阵列计算全国产化服务器 多路PCIe的阵列计算全国产化服务器以国产化处理器&#xff08;海光、飞腾ARM、算能RSIC V&#xff09;为主板&#xff0c;扩展6-8路PCIe3.0X4计算卡&#xff1b; 计算卡为全国产化的AI处理卡&#xff08;瑞星微ARM&#xff0c;算能AI&#x…

C++语言学习(五)—— 类与对象(一)

目录 一、类类型的定义 二、类成员的访问控制 2.1 什么是"类内"和"类外" 2.2 对于访问控制属性的说明 三、类类型的使用 3.1 进行抽象 3.2 声明类 3.3 实现类 3.4 使用类 四、构造函数的引入 五、析构函数的引入 六、重载构造函数的引入 6.1 …