首页 > 其他分享 >多态相关知识2

多态相关知识2

时间:2024-07-04 13:29:53浏览次数:11  
标签:函数 void 知识 多态 virtual 基类 相关 public cout

多态相关知识2

抽象基类和纯虚函数

在设计时,常常希望基类仅仅作为其派生类的一个接口。这就是说,仅想对基类进行向上类型转换,使用它的接口,而不希望用户实际的创建一个基类的对象。同时创建一个纯虚函数允许接口中放置成员原函数,而不一定要提供一段可能对这个函数毫无意义的代码。

做到这点,可以在基类中加入至少一个纯虚函数(pure virtual function),使得基类称为抽象类(abstract class).

  1. 纯虚函数使用关键字virtual,并在其后面加上=0。如果试图去实例化一个抽象类,编译器则会阻止这种操作。
  2. 当继承一个抽象类的时候,必须实现所有的纯虚函数,否则由抽象类派生的类也是一个抽象类。
  3. Virtual void fun() = 0;告诉编译器在vtable中为函数保留一个位置,但在这个特定位置不放地址。

建立公共接口目的是为了将子类公共的操作抽象出来,可以通过一个公共接口来操纵一组类,且这个公共接口不需要事先(或者不需要完全实现)。可以创建一个公共类.

案例: 模板方法模式
在这里插入图片描述

//抽象制作饮品
class AbstractDrinking{
public:
	//烧水
	virtual void Boil() = 0;
	//冲泡
	virtual void Brew() = 0;
	//倒入杯中
	virtual void PourInCup() = 0;
	//加入辅料
	virtual void PutSomething() = 0;
	//规定流程
	void MakeDrink(){
		Boil();
		Brew();
		PourInCup();
		PutSomething();
	}
};

//制作咖啡
class Coffee : public AbstractDrinking{
public:
	//烧水
	virtual void Boil(){
		cout << "煮农夫山泉!" << endl;
	}
	//冲泡
	virtual void Brew(){
		cout << "冲泡咖啡!" << endl;
	}
	//倒入杯中
	virtual void PourInCup(){
		cout << "将咖啡倒入杯中!" << endl;
	}
	//加入辅料
	virtual void PutSomething(){
		cout << "加入牛奶!" << endl;
	}
};

//制作茶水
class Tea : public AbstractDrinking{
public:
	//烧水
	virtual void Boil(){
		cout << "煮自来水!" << endl;
	}
	//冲泡
	virtual void Brew(){
		cout << "冲泡茶叶!" << endl;
	}
	//倒入杯中
	virtual void PourInCup(){
		cout << "将茶水倒入杯中!" << endl;
	}
	//加入辅料
	virtual void PutSomething(){
		cout << "加入食盐!" << endl;
	}
};

//业务函数
void DoBussiness(AbstractDrinking* drink){
	drink->MakeDrink();
	delete drink;
}

void test(){
	DoBussiness(new Coffee);
	cout << "--------------" << endl;
	DoBussiness(new Tea);
}

纯虚函数和多继承

多继承带来了一些争议,但是接口继承可以说一种毫无争议的运用了。
绝大数面向对象语言都不支持多继承,但是绝大数面向对象对象语言都支持接口的概念,c++中没有接口的概念,但是可以通过纯虚函数实现接口。

接口类中只有函数原型定义,没有任何数据定义。

多重继承接口不会带来二义性和复杂性问题。接口类只是一个功能声明,并不是功能实现,子类需要根据功能说明定义功能实现。

注意:除了析构函数外,其他声明都是纯虚函数。
在这里插入图片描述

在这里插入图片描述

虚析构函数

虚析构函数作用

虚析构函数是为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象。

class People{
public:
	People(){
		cout << "构造函数 People!" << endl;
	}
	virtual void showName() = 0;
	virtual ~People(){
		cout << "析构函数 People!" << endl;
	}
};

class Worker : public People{
public:
	Worker(){
		cout << "构造函数 Worker!" << endl;
		pName = new char[10];
	}
	virtual void showName(){
		cout << "打印子类的名字!" << endl;
	}
	~Worker(){
		cout << "析构函数 Worker!" << endl;
		if (pName != NULL){
			delete pName;
		}
	}
private:
	char* pName;
};

void test(){

	People* people = new Worker;
	people->~People();
}

纯虚析构函数

纯虚析构函数在c++中是合法的,但是在使用的时候有一个额外的限制:必须为纯虚析构函数提供一个函数体。

那么问题是:如果给虚析构函数提供函数体了,那怎么还能称作纯虚析构函数呢?

纯虚析构函数和非纯析构函数之间唯一的不同之处在于纯虚析构函数使得基类是抽象类,不能创建基类的对象。

//非纯虚析构函数
class A{
public:
	virtual ~A();
};

A::~A(){}

//纯析构函数
class B{
public:
	virtual ~B() = 0;
};

B::~B(){}

void test(){
	A a; //A类不是抽象类,可以实例化对象
	B b; //B类是抽象类,不可以实例化对象
}

如果类的目的不是为了实现多态,作为基类来使用,就不要声明虚析构函数,反之,则应该为类声明虚析构函数。

重写 重载 重定义

重载,同一作用域的同名函数

  1. 同一个作用域
  2. 参数个数,参数顺序,参数类型不同
  3. 和函数返回值,没有关系
  4. const也可以作为重载条件 //do(const Teacher& t){} do(Teacher& t)

重定义(隐藏)

  1. 有继承
  2. 子类(派生类)重新定义父类(基类)的同名成员(非virtual函数)

重写(覆盖)

  1. 有继承
  2. 子类(派生类)重写父类(基类)的virtual函数
  3. 函数返回值,函数名字,函数参数,必须和基类中的虚函数一致
class A{
public:
	//同一作用域下,func1函数重载
	void func1(){}
	void func1(int a){}
	void func1(int a,int b){}
	void func2(){}
	virtual void func3(){}
};

class B : public A{
public:
	//重定义基类的func2,隐藏了基类的func2方法
	void func2(){}
	//重写基类的func3函数,也可以覆盖基类func3
	virtual void func3(){}
};

标签:函数,void,知识,多态,virtual,基类,相关,public,cout
From: https://blog.csdn.net/2401_83614570/article/details/140153646

相关文章

  • 【C语言小知识】备选拼写:iso646.h头文件
    备选拼写:iso646.h头文件C语言中有3种逻辑运算符:逻辑运算符含义&&与||或!非假设exp1和exp2是俩个简单的关系表达式,那么当且仅当exp1和exp2都为真时,exp1&&exp2才为真。如果exp1或exp2为真,则exp1||exp2为真。如果exp1为假,则!exp为真;如果exp1为真,则!exp为假。i......
  • Python基础小知识问答系列-列表元素次数统计
    1.问题:    怎样统计列表中元素出现次数?    怎样获得列表中元素出现次数排在前n的元素?    怎样汇总两个列表中元素出现次数的信息?2.解决方法:    使用collections模块中的Counter函数。示例:importcollectionsdemo_list=["张共","......
  • Python基础小知识问答系列-字典列表根据字典key排序
    1.问题:    现有一个列表,需要根据字典元素的某个键,进行排序,该怎样实现?2.解决方法:    排序使用sorted函数,通过operator模块中的itemgetter函数实现指定key。示例:fromoperatorimportitemgetterfrompprintimportpprinttest_list=[1,3,6,2,9,......
  • 【基础知识】497- 一文读懂Base64编码
    看到一篇特别好的文章:https://cloud.tencent.com/developer/article/1584718,感谢大佬分享。  一、为什么要使用base64我们知道一个字节可表示的范围是0~255(十六进制:0x00~0xFF),其中ASCII值的范围为0~127(十六进制:0x00~0x7F);而超过ASCII范围的128~255(十六进制:0x80~0......
  • Web基础知识扫盲
    1、中间件定义:中间件是一种独立的系统软件服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源,中间件位于客户机服务器的操作系统之上,管理计算资源和网络通信。常见的中间件:IIS、Apache、Nginx、Tomcat2、NAT网络地址转换这里只介绍动态转换一种动态转换:是指将内部......
  • IIS(Internet Information Services)是Windows操作系统中的一种Web服务器软件。以下是一
    IIS(InternetInformationServices)是Windows操作系统中的一种Web服务器软件。以下是一些常见的与IIS相关的命令和工具:IISRESET:作用:重启IIS服务。语法:iisreset[/noforce][/restart][/stop][/start][/status][/reboot][/help]APPCMD:作用:用于配置IIS7.x及以上版......
  • 计算机网络知识普及之四元组
    在涉及到TCP/UDP等IP类通信协议时,存在四元组概念这里只是普及使用先来一些前置知识,什么是IP协议?IP协议全称为互联网协议,处于网络层中,主要作用是标识网络中的设备,每个设备的IP地址是唯一的。在网络传输中,IP地址主要用于数据包的寻址。目前IP协议主要有两个版本,IPv4和IPv6,......
  • csrf跨站请求,钓鱼网站实现示例,CSRF校验,CSRF相关装饰器,Auth模块,扩展Auth表
    ⅠDjango框架之csrf跨站请求【一】跨站请求伪造介绍【1】引入CSRF(Cross-SiteRequestForgery)跨站请求伪造是一种常见的网络攻击方式。攻击者通过诱导受害者访问恶意网站或点击恶意链接将恶意请求发送到目标网站上利用受害者在目标网站中已登录的身份来执行某些操作从而......
  • 一些关于flume的知识知识碎片
    Flume架构Flume概述flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(比如文本、HDFS、Hbase等)的能力。flume的数据流由事件(Event)贯穿始终......
  • 初学vue3, 全是黑盒子,vue3知识点汇总
    学习Vue.js应该像学习一门编程语言一样,首先要熟练掌握常用的知识,而对于不常用的内容可以简单了解一下。先对整个框架和语言有一个大致的轮廓,然后再逐步补充细节。千万不要像学习算法那样,一开始就钻牛角尖。前序:vueAPI的风格分为:选项式和组合式,vue2中一般用选项式,所以文章......