ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【C++】面向对象之多态篇

2022-02-06 17:05:51  阅读:197  来源: 互联网

标签:函数 double calcArea 多态 C++ 面向对象 Shape Circle Rect


文章目录

6.1 多态概述

当发出一条命令时,不同对象接收到相同的命令后,所作出的动作不同。

严谨说:相同对象收到不同消息 or 不同对象收到相同消息时产生不同的动作

6.2 虚函数机器实现原理

6.2.1 静态多态(早绑定)

class Rect{
public:
	int calcArea(int width);
	int calcArea(int width,int height);
};

定义的一个矩形类Rect中,定义2个成员函数(名字相同),但是2个函数的参数不同,他们是互为重载的函数。

静态绑定:根据传参的个数,计算机在编译时自动地调用相应的函数,即在运行前的编译阶段,函数的程序(调用哪个)已经确定下来了

6.2.2 动态多态(晚绑定)

1.小栗子

圆形类和矩形类(不同对象)分别由自己的计算机面积的方法,但方法不同,即下达相同命令给不同对象,却做着不同的操作。

动态多态的前提:以封装和继承为基础
在一个形状类Shape类中,定义了一个成员函数(计算面积):

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

再定义2个类,这两个类都是以public方式继承shape类。
先是圆形类:

class Circle:public Shape{
public:
	Circle(double r){//构造函数
		m_dR=r;
	}
	double calcArea();
private:
	double m_dR;
};
double Circle::calcArea(){
	return 3.14*m_dR*m_dR;
}

再是矩形类:

class Rect:public Shape{
public:
	Rect(double width,double height){//构造函数
		m_dWidth=width;
		m_dHeigth=height;
	}
	double calcArea();
private:
	double m_dWidth;
	double m_dHeigth;
};
double Rect::calcArea(){
	return m_dWidth*m_dHeight;
}

在main函数中使用时,
可以使用父类的指针shape1指向其中的一个子类对象Circle,
并且用另一个父类指针shape2指向一个矩形的对象。
这两个子类对象都被它的父类指针所指向。

int main(){
	Shape *shape1=new Circle(4.0);
	Shape *shape2=new Rect(3.0,5.0);
	shape1->calcArea();
	shape2->calcArea();
	return 0;
}

输出的结果是2个calcArea().

2.虚函数:

采用virtual修饰类的成员函数。

在父类shape中定义成员函数时,就把我们想要实现多态的成员函数前加virtual关键字(使其成为成员虚函数):

虚函数——“虚假”的函数,父类引用子类对象,子类成员函数重写父类方法(函数)

写法:即将基类的calcArea函数前加virtual,和子类Circle和子类Rect的calcArea函数声明前面加上virtual。

#include<stdlib.h>
#include<iostream>
#include<stdio.h>
using namespace std;

class Shape{
public:
	virtual double calcArea(){//虚函数
		cout<<"calcArea()"<<endl;
		return 0;
	}
};
class Circle:public Shape{
public:
	//Circle(double r);
	virtual double calcArea();
	Circle(double r){//构造函数
		m_dR=r;
	}
private:
	double m_dR;
};
double Circle::calcArea(){//成员函数
	return 3.14*m_dR*m_dR;
}

class Rect:public Shape{
public:
	Rect(double width,double height){//构造函数
		m_dWidth=width;
		m_dHeigth=height;
	}
	virtual double calcArea();
private:
	double m_dWidth;
	double m_dHeigth;
};
double Rect::calcArea(){//成员函数的实现
	return m_dWidth*m_dHeigth;
}

int main(){
	Shape *shape1=new Circle(4.0);
	Shape *shape2=new Rect(3.0,5.0);
	cout<<shape1->calcArea();
	cout<<shape2->calcArea();
	system("pause");
	return 0;
}

输出结果不再是2个calcArea(),而是调用了2个子类中重写基类的calcArea()函数,分别计算出圆和矩形的面积。
在这里插入图片描述
虚函数——“虚假”的函数,父类引用子类对象,子类成员函数重写父类方法。

6.3 虚函数代码实践

在主调程序中定义2个Shape类的指针(一个指向子类Rect,一个指向子类Circle)。

用两个指针分别调用计算面积的函数——看调用的父类的还是子类的面积函数;

最后将2个指针对象销毁——看销毁父类指针时,能否销毁子类的对象。

1.项目结构

在这里插入图片描述

2.3个头文件

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

3.cpp文件

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

Circle::Circle(double r){
	cout<<"Circle()"<<endl;
	m_dR=r;
}
Circle::~Circle(){
	cout<<"~Circle()"<<endl;
}
double Circle::calcArea(){
	cout<<"Circle----calcArea"<<endl;
	return 3.14*m_dR*m_dR;
}
#include<iostream>
#include<stdlib.h>
#include"Circle.h"
#include"Rect.h"
using namespace std;

int main(){
	Shape *shape1=new Rect(3,6);//传入宽和高
	Shape *shape2=new Circle(5);//传入半径
	shape1->calcArea();
	shape2->calcArea();

	delete shape1;
	shape1=NULL;
	delete shape2;
	shape2=NULL;

	system("pause");
	return 0;
}
#include "Rect.h"
#include<iostream>
using namespace std;

Rect::Rect(double width,double height){
	cout<<"Rect()"<<endl;
	m_dWidth=width;
	m_dHeight=height;
}
Rect::~Rect(){
	cout<<"~Rect()"<<endl;
}
double Rect::calcArea(){
	cout<<"Rect----calcArea"<<endl;
	return m_dWidth*m_dHeight;
}

主函数

#include"Shape.h"
#include<iostream>
using namespace std;

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

程序分析

(1)前四行结果:
实例化一个Rect对象
——会先执行父类的构造函数,再执行本身的构造函数。Circle实例化同理。

(2)中间两行
没有做到我们所想的调用Rect和Circle中的calcArea()函数
——解决方案:在3个头文件中的calcArea()函数前加上virtual
注意子类的calcArea函数前的virtual不是一定要加上的,不加上系统也会自动加上,但是最好加上。
都加了virtual后的结果:
在这里插入图片描述
(3)最后两行
销毁Shape1和Shape2时,只执行父类的析构函数,并没有执行2个子类的析构函数。

6.4 虚析构函数

6.5 虚函数和虚析构函数实现原理

(1)函数指针

(2)函数的覆盖与隐藏

(3)虚析构函数的实现原理

(4)虚函数表的代码实践

6.6 纯虚函数和抽象类

(1)纯虚函数的实现原理

(2)纯虚函数和抽象类的代码实践

6.7 接口类

(1)接口类

(2)接口类代码实践

6.8 RTTI:运行时类型识别

(1)RTTI–运行时类型识别

(2)RTTI代码实践

6.9 异常处理

(1)异常处理

(2)异常处理与多态的关系

(3)异常处理代码实践

标签:函数,double,calcArea,多态,C++,面向对象,Shape,Circle,Rect
来源: https://blog.csdn.net/qq_35812205/article/details/122799197

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有