首页 > 编程语言 >C/C++语言基础--C++神奇的多态

C/C++语言基础--C++神奇的多态

时间:2024-10-12 18:22:23浏览次数:9  
标签:函数 -- 子类 void 多态 C++ int 父类 指针

本专栏目的

  • 更新C/C++的基础语法,包括C++的一些新特性

前言

  • 通过前面几节课,我们学习了抽象、封装、继承相关的概念,接下来我们将讲解多态,多态他非常神奇,正式有了他,类才能出现多样性特征;
  • C语言后面也会继续更新知识点,如内联汇编;
  • 欢迎收藏 + 关注,本人将会持续更新。

文章目录

问题思考?

如果子类定义了与父类中定义相同函数会发生什么?如下面代码所示:

#include <iostream>

using namespace std;

class Parent
{
public:
	void show() {
		cout << "I am father" << endl;
	}
};

class Son : public Parent
{
public:
	void show() {
		cout << "I am son" << endl;
	}
};

void print(Parent& p) {
	p.show();
}

int main()
{
	Parent pa;
	Son so;

	print(pa);
	print(so);  // 子赋值给父亲,可以当作父亲用

	return 0;
}

输出:

I am father
I am father

但是,如何在传入不同对象的时候输出相应的数据呢? 这个就是我们接下来要学的多态。

面向对象新需求

上面的这一种场景,需要C++需要做的事情是:

  • print函数中,传递什么对象调用什么对象的show函数,传递父类的,就调用父类的,传递子类的,就调用子类的。

解决方案:虚函数

  • 在父类中,在能让子类重写的函数前面必须加上virtual关键字
  • 在子类中,在重写的父类的虚函数后面加上override关键字,表示是虚函数重写(非必须,但是加上可以防止重写的虚函数写错)

虚函数重写概念

派生类(父类)中有一个跟基类(子类)完全相同的函数(即派生类虚函数与基类虚函数的返回值类型、函数名、参数列表完全相同)

多态的意义探究

面向对象三大概念:

封装:提取事物的属性与方法
继承:代码复用——可以用父类的代码
多态:在代码复用基础上,实现不同功能

案例:打印矩形和圆形坐标和面积

矩形:x,y,length,width

圆形:x,y,radius

在这个案例中,我们可以划分:

  • 封装:将矩形和圆形共有属性抽象出来,这里是x,y坐标,同时将共有方法抽象出来,这里是打印坐标和面积,将这些封装成一个基类A
  • 继承:分别定义矩形、圆形类,继承基类A,同时定义属于自己的属性或者方法,这里是矩形中定义属性length,width,圆形定义radius;
  • 多态:基类中定义了方法(打印坐标和面积),在圆形和矩形中分别重写这两个方法;
  • 测试:利用子类可以赋值给父类的特征,实现传入什么类就输出什么类对应的API。

代码实现如下:

#include <iostream>

using namespace std;

class Geometry
{
public:
	Geometry(int x, int y) : m_x(x), m_y(y) {}

	virtual void print_coordinates() {}

	virtual void print_area() {}

	int m_x;			// 测试:整形
	int m_y;
};

class Rectangle : public Geometry
{
public:
	Rectangle(int x, int y, int width, int length)
		: Geometry(x, y),
		m_width(width),
		m_length(length) {

	}

	// 重写
	void print_coordinates() override
	{
		std::cout << "x: " << m_x << " y: " << m_y << std::endl;
	}

	void print_area() override
	{
		std::cout << "Rectangle area: " << m_width * m_length << std::endl;
	}

	int m_width;
	int m_length;
};

class Round : public Geometry
{
public:
	Round(int x, int y, int riduas)
		: Geometry(x, y),
		m_riduas(riduas)
	{

	}

	// 重写
	void print_coordinates() override
	{
		std::cout << "x: " << m_x << " y: " << m_y << std::endl;
	}

	void print_area() override
	{
		std::cout << "Round area: " <<  3.14 * m_riduas * m_riduas << std::endl;
	}

	int m_riduas;
};

void test(Geometry& various)
{
	various.print_coordinates();
	various.print_area();
}

int main()
{
	Rectangle rect(1, 2, 3, 4);
	Round round(5, 6, 1);

	test(rect);
	test(round);

	return 0;
}

输出:

x: 1 y: 2
Rectangle area: 12
x: 5 y: 6
Round area: 3.14

多态成立的三要素:(结合解决方案)

  1. 要有继承:多态发生在父子类之间
  2. 要有虚函数重写:重写了虚函数,才能进行动态绑定
    1. (解决方案)
  3. 要有父类指针(引用)指向子类对象,传递参数的时候必须为引用或者指针,推荐常引用

虚析构

前置知识:

构造函数不能是虚函数。建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数

析构函数可以是虚的。通过父类指针释放所有的子类资源

虚析构:

虚析构:通过父类去释放子类的时候,如果分类没有虚析构不会调用子类的析构函数的,会调用子类的析构函数,想要通过父类去释放子类, 必须在父类定义虚析构


让我们来看一下,这段代码结果会是什么:

#include <iostream>

using namespace std;

class Base
{
public:
	Base()
	{
		cout << __FUNCSIG__ << endl;
	}
	~Base()
	{
		cout << __FUNCSIG__ << endl;
	}
};

class Derive : public Base
{
private:
	char* _str;
public:
	Derive()
	{
		_str = new char[10] { "wy" };
		cout << __FUNCSIG__ << endl;
	}
	~Derive()
	{
		delete _str;
		cout << __FUNCSIG__ << endl;
	}
};


int main()
{
	Base* base = new Derive;       
	delete base;			
	return 0;
}

结果:

__cdecl Base::Base(void)
__cdecl Derive::Derive(void)
__cdecl Base::~Base(void)

但是这个时候,子类的内存没有释放(_str),这样就造成了内存泄露问题

标签:函数,--,子类,void,多态,C++,int,父类,指针
From: https://blog.csdn.net/weixin_74085818/article/details/142883623

相关文章

  • 面试官:说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢?
    一、为什么要划分使用vue构建项目,项目结构清晰会提高开发效率,熟悉项目的各种配置同样会让开发效率更高在划分项目结构的时候,需要遵循一些基本的原则:文件夹和文件夹内部文件的语义一致性单一入口/出口就近原则,紧耦合的文件应该放到一起,且应以相对路径引用公共的文件应该......
  • 2024.10.12总结
    本文于github博客同步更新你他妈管这个叫noip模拟赛?A:对于上述整除式的一组解\((c,s)\),在\(c\leqa\leqA\)且\(s\leqb\leqB\)时,会被统计入答案,因此它对答案的贡献为\((A-c-1)(B-s-1)\)。在\(s>x\)时,注意到\(\frac{s}{s+x}>\frac{1}{2}\),\(\frac{c}{c+......
  • 什么是虚拟DOM?如何实现一个虚拟DOM?说说你的思路
    一、什么是虚拟DOM虚拟DOM(VirtualDOM)这个概念相信大家都不陌生,从React到Vue,虚拟DOM为这两个框架都带来了跨平台的能力(React-Native和Weex)实际上它只是一层对真实DOM的抽象,以JavaScript对象(VNode节点)作为基础的树,用对象的属性来描述节点,最终可以通过一......
  • 实验一 现代C++编程初体验
    case1://现代C++标准库、算法库体验//本例用到以下内容://1.字符串string,动态数组容器类vector、迭代器//2.算法库:反转元素次序、旋转元素//3.函数模板、const引用作为形参#include<iostream>#include<string>#include<vector>#include<algorithm>usi......
  • 从HCI层浅析BLE Audio通话建立流程
    背景BLEAUDIO音乐播放已经调通了,接下来调试BLEAUDIO的通话,BLEAUDIO通话跟音乐协议类似,都是走CIS链路,也是用同样的codec,比经典蓝牙音乐和通话分别采用不同的A2DP和HFP显得协调多了,下面还是以手机和2个蓝牙耳机为例,结合HCILOG来分析LEAUDIO通话协议的建立:连接建立过程......
  • 并发爬虫_使用motor保存数据
    1importredis2importchardet3importhashlib4importasyncio5importaiohttp6fromlxmlimportetree7fromfake_useragentimportUserAgent8frommotor.motor_asyncioimportAsyncIOMotorClient91011classCarSpider:12user_agent=......
  • Linux的zookeeper安装部署
    1.zookeeper是一个分布式的,开放源码的分布式应用程序协调服务,是hadoop和HBASE的重要组件2.下载zookeeper安装包zookeeper安装包https://archive.apache.org/dist/zookeeper/zookeeper-3.5.9/移动到Linux解压解压到/export/server文件夹命令:   tar-xvfapache-zoo......
  • 近期特别火的巴基斯坦slots游戏投放网盟cpi广告优势
    近期特别火的巴基斯坦slots游戏投放网盟cpi广告优势巴基斯坦是当今一个很火的市场,许多游戏开发商都希望能够进入该市场并取得成功。其中,slot游戏是很受巴基斯坦玩家欢迎的类型之一。为了将这些游戏推广给更多的玩家,许多开发商选择借助网盟cpi广告投流策略。CPI(CostPerInsta......
  • 巴铁火出圈的slots博弈游戏投放Facebook企业广告独家优势
    巴铁火出圈的slots博弈游戏在投放Facebook企业广告方面有以下优势:广告定位准确:Facebook提供了精准的广告定位功能,使得巴铁火能够将广告准确地投放给感兴趣的用户。通过Facebook的用户行为和兴趣标签,巴铁火可以将广告展示给那些可能对博弈游戏感兴趣的用户,提高广告的点击率和......
  • 高频SQL50题(基础版)
    前言:本篇文章主要是更新有关查询的基础SQL题,后续会持续更新连接,聚合函数等类型的sql题目录1757.可回收且低脂的产品(简单)584.寻找用户推荐人(简单)595.大的国家(简单)1148.文章浏览I(简单)1683.无效的推文(简单)1757.可回收且低脂的产品(简单)表:Products+-------------+-------......