【多态性与虚函数的知识点】

多态性与虚函数的知识点

多态:

  1. 多态:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。(消息,就是指调用函数)

  2. 多态性分为两类:静态多态和动态多态。
    静态多态是通过函数的重载实现的,动态多态的特点是:不在编译时确定运行那个程序,而是在程序运行的过程中才确定操作所针对的对象。(运行时多态,是通过虚函数实现的)
    即如果通过对象名调用虚函数,属于静态关联。如果通过基类指针调用虚函数,为动态关联。

虚函数:

虚函数:

就是在基类声明函数是虚拟的,并不是实际存在的函数,然后在派生类中才正式定义的函数。

虚函数的作用:

允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

虚函数的声明方法:

virtual 函数类型 函数名();

虚函数的使用方法:

(1)在类外定义虚函数时,不必再加virtual。
(2)在派生类中重新定义此函数,函数名,函数类型,函数参数个数和类型必须与基类的虚函数相同。
(3)当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。
(4)定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。
(5)通过指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。
静态关联(函数重载)、早期关联/动态关联/滞后关联(程序运行阶段的多态性)

虚函数使用注意:

(1)只能使用virtual声明类的成员函数,而不能将类外的普通函数声明为虚函数。

(2)一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非virtual的但是与该虚函数具有相同的参数(包括个数和类型)和返回值类型的同名函数。

虚析构函数:

virtual ~classname( ) { … }
如果将基类的析构函数声明为虚函数,由该基类所派生的析构函数也都自动成为虚函数(即使派生类的析构函数与基类的析构函数名字不相同)。最好把基类的析构函数声明为虚函数。

纯虚函数与抽象类:

virtual 函数类型 函数名( 参数列表 ) =0;
纯虚函数没有函数体。 如果一个类中声明了纯虚函数,而在其派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。
抽象类:

1、唯一目的的就是用它去建立派生类,不能用来定义对象,只做为一种基本类型。
2、凡是包含纯虚函数的类都是抽象类,因为纯虚函数是不能被调用的,包含纯虚函数的类是无法建立对象的。
3、虽然抽象类不能定义对象,但是可以定义指向抽象类数据的指针变量

多态与虚函数的实例:

1.编写一个程序,声明抽象基类Shape,由它派生出3个派生类:Circle(圆形)、Rectangle(矩形)、Triangle(三角形),用一个函数pritArea分别输出以上三者的面积,3个图形的数据在定义对象时给定。

#include<iostream>
using namespace std;
class Shape //定义抽象基类Shape
{
public:
	virtual double area() const = 0; //纯虚函数
};

class Circle :public Shape //定义Circle类
{
public:
	Circle(double r) :radius(r) {} //结构函数
	virtual double area() const { return 3.14159 * radius * radius; }; //定义虚函数
protected:
	double radius; //半径
};

class Rectangle :public Shape //定义Rectangle类
{
public:
	Rectangle(double w, double h) :width(w), height(h) {} //结构函数
	virtual double area() const { return width * height; } //定义虚函数
protected:
	double width, height; //宽与高
};

class Triangle :public Shape //定义Triangle类
{
public:
	Triangle(double w, double h) :width(w), height(h) {} //结构函数
	virtual double area() const { return 0.5 * width * height; } //定义虚函数
protected:
	double width, height; //宽与高
};

void printArea(const Shape& s) //输出面积的函数
{
	cout << s.area() << endl;
}

int main()
{
	Circle circle(12.6); //建立Circle类对象circle
	cout << "area of circle=";
	printArea(circle); //输出circle的面积

	Rectangle rectangle(4.5, 8.4); //建立Rectangle类对象rectangle
	cout << "area of rectangle=";
	printArea(rectangle); //输出rectangle的面积

	Triangle triangle(4.5, 8.4); //建立Triangle类对象
	cout << "area of triangle=";
	printArea(triangle); //输出triangle的面积

	return 0;
}

2.编写一个程序,定义抽象基类Shape,由它派生出5个派生类:Cricle(圆形),Square(正方形), Rectangle(矩形), Trapezoid(梯形),Triangle(三角形)。用虚函数分别计算图形面积,并求所有图形面积的和。要求用基类指针数组,使它的每一个元素指向一个派生类对象。

#include<iostream>
using namespace std;
class Shape //定义抽象基类Shape
{
public:
	virtual double area() const = 0; //纯虚函数
};

class Circle :public Shape //定义Circle(圆形)类
{
public:
	Circle(double r) :radius(r) {} //构造函数
	virtual double area() const { return 3.14159 * radius * radius; }; //定义虚函数
protected:
	double radius; //半径
};

class Square :public Shape //定义Square(正方形)类
{
public:
	Square(double s) :side(s) {} //构造函数
	virtual double area() const { return side * side; }  //定义虚函数
protected:
	double side;

};

class Rectangle :public Shape //定义Rectangle(矩形)类
{
public:
	Rectangle(double w, double h) :width(w), height(h) {} //结构函数
	virtual double area() const { return width * height; } //定义虚函数
protected:
	double width, height; //宽与高
};

class Trapezoid :public Shape //定义Trapezoid(梯形)类
{
public:
	Trapezoid(double t, double b, double h) :top(t), bottom(t), height(h) {} //结构函数
	virtual double area() const { return 0.5 * (top + bottom) * height; } //定义虚函数
protected:
	double top, bottom, height; //上底、下底与高
};

class Triangle :public Shape //定义Triangle(三角形)类
{
public:
	Triangle(double w, double h) :width(w), height(h) {} //结构函数
	virtual double area() const { return 0.5 * width * height; } //定义虚函数
protected:
	double width, height; //宽与高
};

int main()
{
	Circle circle(12.6); //建立Circle类对象circle
	Square square(3.5); //建立Square类对象square
	Rectangle rectangle(4.5, 8.4); //建立Rectangle类对象rectangle
	Trapezoid trapezoid(2.0, 4.5, 3.2); //建立Trapezoid类对象trapezoid
	Triangle triangle(4.5, 8.4); //建立Triangle类对象
	Shape* pt[5] = { &circle,&square,&rectangle,&trapezoid,&triangle }; //定义基类指针数组pt,使它每一个元素指向一个派生类对象
	double areas = 0.0; //areas为总面积
	for (int i = 0; i < 5; i++) areas = areas + pt[i]->area(); //累加面积
	cout << "total of all areas=" << areas << endl; //输出总面积
	return 0;
}

多态性与虚函数的实验结果

多态与虚函数的实例1:

在这里插入图片描述

多态与虚函数的实例2:

在这里插入图片描述


总结:通过这次实验了解到,如果在基类中定义了没有参数的构造函数,那么在定义派生类构造函数时可以不写基类构造函数,在调用派生类构造函数时、系统会自动首先调用基类的默认构造函数、如果在基类或子对象类型的声明中定义了参数的构造函数、那么就必须显式地定义派生类构造函数。动态联编需要满足3个条件,首先类之间满足类型兼容规则:第二是要声明虚函数:第三是要由成员函数来调用或者是通过基类指针、引用来访问虚函数。继承时,子类对基类的访问属性、基类的私有成员无论以何种方式继承在子类中都是不可访问的。唯有调用基类中的成员函数方可访问其私有变量。另外、派生类构造函数的总参数列表中的参数,应当包括基类构造函数和子对象的参数列表中的参数。而多层派生时、只需写出其直接基类的构造函数即可。虚函数可以让代码重用,用一个界面的不同表示方法,增加功能的分类,使相近的功能不同但是类似的表示,同时虚函数和多态的使用在程序更新时让类库更加方便。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值