C++ 多态(1): 虚函数及实现原理

C++远征之多态篇 视频教程 笔记 方便自己查阅和复习,温故而知新。

目录

1 虚函数及实现原理

2 代码示例1

3 代码示例2

参考资料


 

多态

多态指相同对象接收到不同消息或不同对象收到相同消息时产生不同的动作。

多态分为静态多态动态多态

(1) 静态多态也称为早绑定。

(2) 动态多态也称为晚绑定,必须以封装和继承为基础。


 

1 虚函数及实现原理

(1) 静态多态(早绑定)

例如,对于下面的两个函数重载,那么,实例化对象后,可以分别调用这两个函数,因为参数个数不同,计算机在编译的时候,自动识别时调用的函数。在程序运行之前,在编译阶段,就已经确定了使用哪个函数,我们称之为:静态多态 (早绑定)

 

 

 


 

(2) 动态多态(晚绑定)

 

 

注: 动态多态必须以 封装 继承 为基础

 

 

 

 

 

 

 

调用的都是父类计算面积的函数。那么如何去调用子类的计算面积的函数呢? 这是 将用到 虚函数(virtual) ,这个在继承篇也用到虚函数了。

 

直接在 父类和子类计算面积的函数 声明前面 加上关键字 virtual 即可

 

 

 

注:子类可以不添加关键字 virtual,但是推荐在子类前面加上,方便查看代码。

 


2 代码示例1

要求:

动态多态 虚函数
1 定义Shape类
    成员函数:calcArea() 构造函数 析构函数 

2 线段类:Line
    数据成员: m_dWidth m_dHeight 
    成员函数:calcArea() 构造函数 析构函数 

3 定义Circle类
    成员函数: m_dR
    数据成员:calcArea() 构造函数 析构函数

//Shape.h

#pragma once
#include<iostream>
using namespace std;

class Shape
{
public:
	Shape();
	~Shape();

	virtual double calcArea();

};
//Shape.cpp

#include"Shape.h"


Shape::Shape()
{
	cout << "Shape()--构造" <<endl;
}

Shape::~Shape()
{
	cout << "~Shape()--析构" << endl;
}


double Shape::calcArea()
{
	cout << "Shape--calcArea()" << endl;
	return 0;
}

 

//Rect.h

#pragma once
#include"Shape.h"

class Rect :public Shape
{
public:
	Rect(double width,double height);
	~Rect();
	virtual double calcArea();

protected:
	double m_dWith;
	double m_dHight;
};
//Rect.cpp

#include"Rect.h"

Rect::Rect(double width, double height)
{
	m_dHight = height;
	m_dWith = width;
	cout <<"Rect()--构造"<<endl;
}

Rect::~Rect()
{
	cout << "Rect()--析构" << endl;
}

	
double Rect::calcArea()
{
	cout << "Rect--calcArea()" << endl;
	return m_dWith*m_dHight;
}

 

//Circle.h

#pragma once

#include"Shape.h"

class Circle :public Shape
{
public:
	Circle(double r);
	~Circle();
	virtual double calcArea();

private:
	double m_dR;
};
//Circle.cpp

#include"Circle.h"
Circle::Circle(double r)
{
	m_dR = r;
	cout << "Circle()--构造"<< endl;
}


Circle::~Circle()
{
	cout << "~Circle()--析构" << endl;
}


double Circle::calcArea()
{
	cout << "Circle--calcArea()" << endl;
	return 3.14*m_dR*m_dR;
}

 

//main.cpp

#include<iostream>
#include<string>
#include"Circle.h"
#include"Rect.h"
using namespace std;

/**
动态多态 虚函数
1 定义Shape类
    成员函数:calcArea() 构造函数 析构函数 

2 线段类:Line
    数据成员: m_dWidth m_dHeight 
    成员函数:calcArea() 构造函数 析构函数 

3 定义Circle类
	成员函数: m_dR
	数据成员:calcArea() 构造函数 析构函数
**/

int main()
{
	Shape *shape1 = new Rect(3, 6);
	Shape *shape2 = new Circle(5);
	cout << "---------1-----------" << endl;

	shape1->calcArea();
	cout << "---------2-----------" << endl;
	shape2->calcArea();

	cout << "---------3-----------" << endl;


	delete shape1;
	shape1 = NULL;

	delete shape2;
	shape2 = NULL;
	cin.get();
	return 0;
}

 

运行结果:

注:可以去掉关键字 virtual 查看运行结果,其运行结果如下:

 

从两个结果可以看出 如果不在成员函数前面加入关键字 virtual,将会只执行父类的成员函数,不执行子类的成员函数。

 


3 代码示例2

注:由上面的例子例子看出,在父类指针 指向 子类时,释放内存 只执行了父类的析构函数[ ~shape() ],这可能会造成内存泄漏 这时 需要用 虚函数/虚析构函数 (在父类和子类的虚构函数前加入 virtual )  即可。

 

要求和上面的代码示例相同,只在父类 和 子类 的析构函数前面添加 关键字 virtual 即可。

 

运行结果:

从上面的运行结果可以看出 :父类和子类的析构函数都执行。

 

 virtual在函数中的使用限制

(1) 普通函数不能是虚函数

virtual修饰的必须是某一个类的成员函数,不能是全局函数。

(2) 静态函数不能是虚函数

 

(3) 内联函数不能是虚函数

 

(4) 构造函数不能是虚函数

 

 


 

关于C++其他内容笔记参见

[1] C和C++的主要区别 和 C++面向对象的三大特征

[2] C++ 封装(1): 类和对象

[3] C++ 封装(2): 构造函数和析构函数

[4] C++ 封装(3): 对象成员与对象数组, 深拷贝和浅拷贝

[5] C++ 封装(4): 对象指针, const

[6] C++ 继承(1): 继承方式(public, protected, private), 继承中的特殊关系(隐藏 , is-a)

[7] C++ 继承(2): 多重继承, 多继承, 虚继承(virtual)

 


参考资料

[1] C++远征之多态篇 (注:图片均来自视频中PPT)

 

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechArtisan6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值