第八站:C++面向对象(继承和派生)

news2024/11/28 0:52:45

继承和派生

 派生:由父类派生出子类

继承:子类继承父类(继承不会继承析构函数和构造函数:父类的所有成员函数,以及数据成员,都会被子类继承!)

"子类派生出的类"会指向"父类被继承的类",父类就是基类

实例1:

先创建一个父类,有私有成员数据(name,和age),成员函数,描述信息,有参的构造函数

再创建一个子类,有自己独立的私有成员(game),其余的继承自父类(注:无法继承构造函数)

father.h

#pragma once
#include <string>
using namespace std;
class Father{
public :
	Father(const char* name, int age);
	~Father();
	string getName()const;
	int getAge()const;
	string describe();

private:
	string name;
	int age;
};

 father.cpp

#include "Father.h"
#include <sstream>
#include <iostream>

Father::Father(const char* name, int age) {
	cout << __FUNCTION__ << endl;
	this->name = name;
	this->age = age;
}
Father::~Father() {

}
string Father::getName()const {
	cout << __FUNCTION__ << endl;
	return name;
}
int Father::getAge()const {
	cout << __FUNCTION__ << endl;
	return age;
}
string Father::describe() {
	cout << __FUNCTION__ << endl;
	stringstream ret;
	ret << "姓名:" << name << " 年龄:" << age << endl;
	return ret.str();
}

 son.h

#pragma once
#include "Father.h"
class Son :public Father{//子类son继承父类father
public:
	//子类不会调用父类的构造函数
	Son(const char*name,int age,const char *game);
	~Son();
	string getGame()const;
	string describe();//继承了父类的成员函数,但是需要重写用来描述自己的信息
private:
	string game;
};

son.cpp

#include "Son.h"
#include <sstream>
#include <iostream>
//子类虽然没有继承父类的构造方法,
//但是在继承父类成员数据,进行自写构造方法时,
//会先调用父类的构造方法,进行初始化父类的成员数据,
//然后再调用自己的的构造函数,初始化自己的成员数据
//当没有体现出父类构造函数时,编译器会自动调用父类的默认构造函数
//const char* name, int age这一段就是子类应要调用父类的,需要手动添加
//:Father(name,age)//用于体现父类的构造函数
Son::Son(const char* name, int age, const char* game):Father(name,age) {
	cout << __FUNCTION__ << endl;
	this->game = game;
}
Son::~Son() {

}
string Son::getGame()const {
	cout << __FUNCTION__ << endl;
	return game;
}
string Son::describe() {
	cout << __FUNCTION__ << endl;
	stringstream ret;
	//这里的是无法直接调用name和age的,他们作为父类的私有成员数据
	// 子类虽然继承,但是无法调用,可以通过父类公有的get方法去获取私有的成员数据
	// 也可以使用protected关键字在父类进行说明
	//ret << "姓名:" << name << "年龄:" << age << endl;
	ret << "姓名:" << getName() << " 年龄:" << getAge() << " 游戏:" << game << endl;
	return ret.str();
}

知识点汇总:

1:子类构造函数

不存在默认构造函数

注意:无论创建几个对象,该类的静态成员只构建一次,所有静态成员的构造函数值调用一次

//子类虽然没有继承父类的构造方法,
//但是在继承父类成员数据,进行自写构造方法时,
//会先调用父类的构造方法,进行初始化父类的成员数据,
//然后再调用自己的的构造函数,初始化自己的成员数据
//当没有体现出父类构造函数时,编译器会自动调用父类的默认构造函数
//const char* name, int age这一段就是子类应要调用父类的,需要手动添加
//:Father(name,age)//用于体现父类的构造函数

 

子类父类构造函数调用顺序:
静态数据成员[ 只会调用一次 ]的(外类)构造函数 -> 父类的构造函数 -> 非静态的数据成员的(外类)构造函数 -> 自己的构造函数
#include <iostream>
#include <Windows.h>
using namespace std;
class M {
public:
	M() {
		cout << __FUNCTION__ << endl;
	}
};
class N {
public:
	N() {
		cout << __FUNCTION__ << endl;
	}
};
class A {
public:
	A() {
		cout << __FUNCTION__ << endl;
	}
};
class B : public A {
public:
	B() {
		cout << __FUNCTION__ << endl;
	}
private:
	M m1;
	M m2;
	static N ms;
};
N B::ms{}; //静态成员
int main(void) {
	B b;
	system("pause");
}
子类父类析构函数调用顺序:
静态数据成员[ 只会调用一次 ]的(外类)构造函数 <- 父类的构造函数 <- 非静态的数据成员的(外类)构造函数 <- 自己的构造函数

 

 2:子类重写函数

父类的成员数据无法访问

//这里的是无法直接调用name和age的,他们作为父类的私有成员数据
// 子类虽然继承,但是无法调用,可以通过父类公有的get方法去获取私有的成员数据

ret << "姓名:" << getName() << " 年龄:" << getAge() << " 游戏:" << game << endl;
// 也可以使用protected关键字在父类进行说明

 派生类子类对象的内存分布

 在命令行中添加选项:(打印指定类的内存分布)

成员函数不占内存空间,但是也被子类继承了!!!

//报告单个类的内存分布
/d1 reportSingleClassLayout Father
/d1 reportSingleClassLayout Son
通过sizeof打印他们各自占的内存字节数
cout << sizeof(father) << endl;
cout << sizeof(son) << endl;

 

 

 

 三种访问权限总结

public:外部和子类都可以直接访问

private:外部及子类都无法访问,本类的成员函数内可以访问

protected访问权限:外部无法访问,但是子类可以访问

在不适用protected的前提下,子类访问父类的成员数据,只能通过父类的get成员函数,来访问

但是使用protected访问权限后,子类可以直接访问父类的成员数据,父类的对象依然无法访问成员数据

三种继承方式;

public继承方式:

#include "Father.h"
class Son :public Father

父类中定义的成员(数据成员和函数成员)被继承后,访问权限不变!

public --->public

private--->private

protected---->pritected 

 private继承方式

#include "Father.h"
class Son :private Father

父类中定义的成员(数据成员和函数成员)被继承后,访问权限全部变成private

public --->private

private--->private

protected---->private 

 protected继承方式

#include "Father.h"
class Son :protected Father

protected 继承 只把 public 降级为 protected

public --->protected

private--->private

protected---->private 

 子类型(public继承)

子类继承父类,是父类的派生,子类的对象可以作为基类的对象(形参是基类对象时,实参可以用子类对象)

1. 基类(父类)的指针,可以指向这个类的公有派生类(子类型)对象。
        Son b ;
        Father * a = &b;
2. 公有派生类(子类型)的对象可以初始化基类的引用
        Son b ;
        Father &a = b;
3. 公有派生类的对象可以赋值给基类的对象
        Son b ;
        Father a  = b;

 

#include <iostream>
#include <Windows.h>
using namespace std;
class A {
public :
	A() {};
	void kill() {
		cout << "父类杀敌" << endl;
	}
	
};
class B :public A {
public:
	B() {};
	void kill() {
		cout << "子类杀敌" << endl;
	}
};
void test(A a) {
	a.kill();
}
int main(void) {
	B b;//将子类的对象传给父类的对象
	test(b);
}

多重继承

概念:

将多个基类用逗号隔开.调用基类的顺序和声明基类出现的顺序一致

class D: public A, private B, protected C{
        //类 D 自己新增加的成员
}; 
D 是多继承形式的派生类,
D 3 个父类 ( 基类 )
它以公有的方式继承 A 类,
以私有的方式继承 B 类,
以保护的方式继承 C 类。
D 根据不同的继承方式获取 A B C 中的成员 .

 弊端:

当子类继承的多个基类,中的方法有相同的时候,就会出现二义性,但是可以通过基类名指定调用哪一个基类的方法

Class A{
        void dance(){};
};
Class B{
        void dance(){};
};
class D: public A, public B{
        //类 D 自己新增加的成员
解决二义性方法2:
        void dance(){
                B::dance();
                A::dance();
        };
}; 
int main(void){
        D d;
        d.dance();//这时候就不知道调用谁的方法了
解决二义性方法1:
        d.A::dance();//通过基类名::方法,指定调用哪一个
        d.B::dance();
解决二义性方法2:
        在子类中,指定,( 美观)
        d.dance();//调用自己指定好的,进行调用
}

问题:

但是当子类继承的是多个子类(这些子类继承同一个基类)的时候,就容易出现,指定不明确的时

 public:
    //类 D 自己新增加的
    void setTel(string Tel) {
        this->A::tel = Tel;
    };
    string getTel() {
        return B::tel;
    };

#include <iostream>
#include <string>
using namespace std;
class ALL {
public:
	ALL() {
		this->tel = "未知";
	}
protected:
	string tel;
};
class A : public ALL{
	
};
class B : public ALL{
	
};
class D : public A, public B {
public:
	//类 D 自己新增加的
	void setTel(string Tel) {
		this->A::tel = Tel;
	};
	string getTel() {
		return B::tel;
	};
};
int main(void) {
	D d;
	d.setTel("1234678");
	cout << d.getTel() << endl;
	system("pause");
	return 0;
}

解决二义性弊端问题

使用虚基类和虚继承

此时ALL是虚基类  B,C是虚继承(virtual)

class A : virtual public ALL{ 
};
class B :virtual public ALL{
};

  public:
    //类 D 自己新增加的
    void setTel(string Tel) {
        this->tel = Tel;
    };
    string getTel() {
        return tel;
    };

#include <iostream>
#include <string>
using namespace std;
class ALL {
public:
	ALL() {
		this->tel = "未知";
	}
protected:
	string tel;
};
class A : virtual public ALL{
	
};
class B : virtual public ALL{
	
};
class D : public A, public B {
public:
	//类 D 自己新增加的
	void setTel(string Tel) {
		this->tel = Tel;
	};
	string getTel() {
		return tel;
	};
};
int main(void) {
	D d;
	d.setTel("1234678");
	cout << d.getTel() << endl;
	system("pause");
	return 0;
}

继承小练习:

练习1:

定义一个Book类

查看当前价格 .
查看当前的书号
定义一个类 SellBook, 用来表示促销的书籍 , 要求继承自 Book
具有以下功能 :
1. 查看当前折扣
2. 设置当前折扣
3. 查看当前的促销价格

 .h

Book.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Book
{
public:
	Book(float price ,string isbn);
	~Book();
	float getPrice()const;
	string getIbsn() const;
	void setPrice(float price);
	void setIsbn(string ISBN);
protected:
	float price;
	string IBSN;
};


SellBook.h
#pragma once
#include "Book.h"
class SellBook :public Book{
public:
	SellBook(float price,string isbn,float discount = 1.0);
	~SellBook();
	float getDiscount()const;
	void setDiscount(float discount);
	void setPrice(float price);
	float getPrice()const ;

private:
	float discount;
};

.cpp

Book.cpp
#include "Book.h"

Book::Book(float price, string isbn)
{
	this->price = price;
	this->IBSN = isbn;
}
Book::~Book(){

}
float Book::getPrice()const {
	return price;
}
string Book::getIbsn()const {
	return IBSN;
}
void Book::setPrice(float price) {
	this->price = price;
}
void Book::setIsbn(string isbn) {
	this->IBSN = isbn;
}

SellBook.cpp
#include "SellBook.h"

SellBook::SellBook(float price, string isbn, float discount):Book(price,isbn)
{
	this->discount = discount;
}
SellBook::~SellBook() {

}
float SellBook::getDiscount()const {
	return discount;
}
void SellBook::setDiscount(float discount) {
	this->discount = discount;
}
float SellBook::getPrice() const
{
	return price*discount;
}


main.cpp
#include "Book.h"
#include "SellBook.h"
#include <iostream>
using namespace std;

int main(void) {
	SellBook book1(1200,"123456-123");
	cout << "未折扣前价格: " << book1.getPrice()
		<< "书号:" << book1.getIbsn() << endl;
	cout << endl;
	float n = 0.0;
	cout << "请输入当前的折扣力度: ";
	cin >> n;
	book1.setDiscount(n);
	cout << "当前折扣为: " << book1.getDiscount() << endl;
	cout << "折扣后价格: " << book1.getPrice()
		<< "书号:" << book1.getIbsn() << endl;
	system("pause");
	return 0;
}

 练习2:

某无线通信设备 ODU 设备:
        查看发射功率, 设置发射功率 ,
        查看发射频率, 设置发射频率 ,
        查看带宽, 修改带宽 ,
        查看设备概述( 各指标的值 )
对该产品做了升级 , 研发了 ODU330 产品 :
        查看当前的误码率.
        查看误码率告警门限
        设置误码率告警门限

 .h

ODU.h
#pragma once
#include <string>
using namespace std;
class ODU{
public:
	~ODU();
	ODU();
	int getToPower()const;
	int getToFreq()const;
	int getBandWidth()const;
	void setToPower(int toPower);
	void setToFreq(int toFreq);
	void setBandWidth(int bandWidth);
	string describe();
protected:
	int toPower;
	int toFreq;
	int bandWidth;
};
ODU330.H
#pragma once
#include "ODU.h"
class ODU330 :public ODU{
public:
	ODU330();
	~ODU330();
	float getERate()const;
	float getThresHold()const;
	void setThresHold(float thresHold);
	string describe();
private:
	float ERate = 0.003f;
	float thresHold;
};

.CPP

ODU.CPP
#include "ODU.h"
#include <sstream>
using namespace std;
ODU::ODU() {

}
ODU::~ODU() {

}
int ODU::getToPower()const {
	return toPower;
}
int ODU::getToFreq()const {
	return toFreq;
}
int ODU::getBandWidth()const {
	return bandWidth;
}
void ODU::setToPower(int toPower) {
	this->toPower = toPower;
}
void ODU::setToFreq(int toFreq) {
	this->toFreq = toFreq;
}
void ODU::setBandWidth(int bandW) {
	this->bandWidth = bandW;
}
string ODU::describe() {
	stringstream ret;
	ret << "当前发射功率为: " << toPower << " 当前发射频率为: " << toFreq
		<< " 当前带宽为: " << bandWidth << endl;
	return ret.str();
}
ODU.CPP
#include "ODU330.h"
#include <sstream>
ODU330::ODU330() {

}
ODU330::~ODU330() {
}
float ODU330::getERate()const {
	return ERate;
}
float ODU330::getThresHold()const {
	return thresHold;
}
void ODU330::setThresHold(float thresHold) {
	this->thresHold = thresHold;
}
string ODU330::describe(){
	stringstream ret;
	ret << "当前发射功率为: " << toPower << " 当前发射频率为: " << toFreq
		<< " 当前带宽为: " << bandWidth << "\n"
		<< "新增功能: " << "误码率为: " << ERate << " 告警门限为: " << thresHold <<
		endl;
	return ret.str();
}
main.cpp
#include "ODU.h"
#include "ODU330.h"

#include <iostream>
using namespace std;

int main(void) {
	ODU h1;
	h1.setBandWidth(600);
	h1.setToPower(45);
	h1.setToFreq(115000);
	cout << h1.describe() << endl;

	ODU330 h2;
	h2.setBandWidth(900);
	h2.setToPower(48);
	h2.setToFreq(119000);
	h2.setThresHold(0.00001);
	cout <<h2.describe()<<endl;
}

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

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

相关文章

Flask框架小程序后端分离开发学习笔记《2》构建基础的HTTP服务器

Flask框架小程序后端分离开发学习笔记《2》构建基础的HTTP服务器 Flask是使用python的后端&#xff0c;由于小程序需要后端开发&#xff0c;遂学习一下后端开发。本节提供一个构建简单的本地服务器的代码&#xff0c;仔细看注释&#xff0c;学习每一步的流程&#xff0c;理解服…

react-app框架——使用monaco editor实现online编辑html代码编辑器

文章目录 ⭐前言&#x1f496;react系列文章 ⭐配置monaco-editor&#x1f496;引入react-monaco-editor&#x1f496;引入react-app-rewired&#x1f496;通过config-overrides.js添加monaco插件配置 ⭐编辑代码的react页面配置&#x1f496;扩展 可自定义配置语言 ⭐效果⭐总…

使用 mybatis-plus 的mybaits的一对多时, total和record的不匹配问题

应该是框架的问题&#xff0c;去官方仓库提了个issues&#xff0c;等回复 https://github.com/baomidou/mybatis-plus/issues/5923 背景 发现 record是两条&#xff0c;但是total显示3 使用resultMap一对多时&#xff0c;三条数据会变成两条&#xff0c;但是total确是3条 下…

新能源汽车智慧充电桩方案:基于视频监控的可视化智能监管平台

一、方案概述 TSINGSEE青犀&触角云新能源汽车智慧充电桩方案围绕互联网、物联网、车联网、人工智能、视频技术、大数据、4G/5G等技术&#xff0c;结合云计算、移动支付等&#xff0c;实现充电停车一体化、充电桩与站点管理等功能&#xff0c;达到充电设备与站点的有效监控…

[足式机器人]Part2 Dr. CAN学习笔记-Ch04 Advanced控制理论

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - Ch04 Advanced控制理论 1. 绪论2. 状态空间表达State-Space Representation3. Phase Portrait相图&#xff0c;相轨迹3 1. 1-D3 2. 2-D3 3. General Form3 4. Summary3.5. 爱情中的数学-Phase …

Luckysheet类似excel的在线表格(vue)

参考文档&#xff1a;快速上手 | Luckysheet文档 一、引入 在vue项目的public文件夹下的index.html的<head>标签里面引入 <link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/luckysheetlatest/dist/plugins/css/pluginsCss.css /><link relstylesheet hre…

使用 Neo4j 和 LangChain 集成非结构化知识图增强 QA

目前基于大模型的信息检索有两种方法&#xff0c;一种是基于微调的方法&#xff0c;一种是基于 RAG 的方法。 信息检索和知识提取是一个不断发展的领域&#xff0c;随着大型语言模型&#xff08;LLM&#xff09;和知识图的出现&#xff0c;这一领域发生了显着的变化&#xff0…

河南选调生报名照片上传成功,不能大于50kb

河南选调生报名照片要求&#xff1a; 1、上传近期正面免冠证件照 2、照片背景&#xff1a;要求为蓝底 3、照片格式&#xff1a;jpg格式 4、照片宽高比例约为1.3:1.6&#xff0c;大小为130160像素 5、照片大小&#xff1a;50kb以下&#xff0c;最终效果以输出后的大小为准

pytest学习和使用-pytest如何进行分布式测试?(pytest-xdist)

1 什么是分布式测试&#xff1f; 在进行本文之前&#xff0c;先了解些基础知识&#xff0c;什么是分布式测试&#xff1f;分布式测试&#xff1a;是指通过局域网和Internet&#xff0c;把分布于不同地点、独立完成特定功能的测试计算机连接起来&#xff0c;以达到测试资源共享…

SpringMVC JSON数据处理见解6

6.JSON数据处理 6.1.添加json依赖 springmvc 默认使用jackson作为json类库,不需要修改applicationContext-servlet.xml任何配置&#xff0c;只需引入以下类库springmvc就可以处理json数据&#xff1a; <!--spring-json依赖--> <dependency><groupId>com.f…

群晖搭建LDAP服务器实现一个账号登录DSM、Gitea、jellyfin

文章目录 前言安装LDAP Server新建群组新增用户 DSM加入LDAPDSM使用LDAP登录 Gitea配置登录取消其登录权限 Jellyfin配置登录 总结 前言 LDAP&#xff08;轻量级目录访问协议&#xff09;是一种用于访问和管理分布式目录服务的协议&#xff0c;它具有以下好处&#xff1a; 集…

flutter开发windows桌面软件,使用Inno Setup打包成安装程序,支持中文

最近使用flutter开发windows桌面软件的时候&#xff0c;想要将软件打包成安装程序&#xff0c;使用了flutter官方推荐的msix打包&#xff0c;但是打包出来的软件生成的桌面快捷方式有蓝色背景&#xff1a; 这个蓝色背景应该是没有设置为动态导致的&#xff0c;windows系统的屏幕…

POE工业交换机:点亮灯光控制与建筑自动化的新时代

随着科技的不断发展&#xff0c;灯光控制和建筑自动化在现代建筑中扮演着重要角色。而POE工业交换机作为一种创新的网络设备&#xff0c;不仅能够为灯光控制和建筑自动化提供稳定可靠的网络通信&#xff0c;还具备便捷的供电功能。本文将探讨POE工业交换机对灯光控制和建筑自动…

Unity URP切换品质和Feature开关的性能问题

现在对我的项目进行安卓端发布&#xff0c;需要切换品质和一些Feature开关。 我是这样做的。 划分品质 首先Renerer分为2个Android和PC&#xff0c;图中其他不用参考。 每个副本的URP Asset分为pc和android&#xff0c;例如图中的 hall和hall_android。 我们可以看到hall用的…

【性能调优】local模式模式下flink处理离线任务能力分析

文章目录 一. flink的内存管理1.Jobmanager的内存模型2.TaskManager的内存模型2.1. 模型说明2.2. 通讯、数据传输方面2.3. 框架、任务堆外内存2.4. 托管内存 3.任务分析 二. 单个节点的带宽瓶颈1. 带宽相关理论2. 使用speedtest-cli 测试带宽3. 任务分析3. 其他工具使用介绍 本…

使用CSS计算高度铺满屏幕

前言 今天写项目时出现高度设置百分百却不占满屏幕&#xff0c;第一反应看自己设置的是块级元素还是行级元素。看了几篇博客&#xff0c;发现并不能解决问题。脱离文档流的做法都没考虑&#xff0c;前期模板搭建脱离文档流&#xff0c;后面开发会出现很多问题。 以上图片是我…

几何_直线方程 Ax + By + C = 0 的系数A,B,C几何含义是?

参考&#xff1a; 直线方程 Ax By C 0 的系数A&#xff0c;B&#xff0c;C有什么几何含义&#xff1f;_设直线 l 的方程为axbyc0 怎么理解-CSDN博客 1. A B的含义&#xff1a;组成一个与直线垂直的向量 我们先来看A和B有什么含义。 在直线上取任意两点 P1:&#xff08;x1…

无界面自动化测试(IDEA+Java+Selenium+testng)(PhantomJS)

自动化测试&#xff08;IDEAJavaSeleniumtestng&#xff09;(PhantomJS)_phantomjs怎么写js脚本idea-CSDN博客 上述连接是参考&#xff1a;现在如果按照如上链接进行操作大概率会失败&#xff0c;下面会针对如上链接的部分步骤做出修改 1、在pom.xml文件中需要使用低版本sele…

【Go学习】macOS+IDEA运行golang项目,报command-line-arguments,undefined

写在前面的话&#xff1a;idea如何配置golang&#xff0c;自行百度 问题1&#xff1a;通过idea的terminal执行go test报错 ✘ xxxxxmacdeMacBook-Pro-3  /Volumes/mac/.../LearnGoWithTests/hello  go test go: go.mod file not found in current directory or any parent …

【汇编】 13.3 对int iret和栈的深入理解

书中示例 assume cs:codecode segment start:mov ax,csmov ds,axmov si,offset lpmov ax,0mov es,axmov di,200hmov cx,offset end0-offset lpcldrep movsb ;lp到end0的指令传送到0:200处mov ax,0mov es,axmov word ptr es:[7ch*4],200hmov word ptr es:[7ch*42],0 ;设置7c表项…