题目要求
定义抽象基类 Shape,由它派生出3个派生类: Circle(圆形)、Rectangle(矩形)、Triangle(三角形),用一个函数 printArea 分别输出以上三者的面积,3个图形的数据在定义对象时给定。
——谭浩强的《C++面向对象程序设计》第6章习题第4小题
虚函数
虚函数,就是在基类声明函数是虚拟的,在派生类中才正式定义的函数。虚函数的作用就是在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
在运用虚函数后,基类指针指向派生类对象,就能调用派生类的虚函数。用同一指针变量,可以调用同一类族中不同类的虚函数,也就是对同一消息,不同对象有不同的响应方式。
虚函数声明格式:
virtual <返回类型> <函数名> (<参数表>) {<函数体>}
如果某类中的一个成员函数被说明为虚函数,则意味着该成员函数在派生类中可能存在着不同的实现。
基类中用 virtual 声明成员函数为虚函数。在派生类中重新定义同名函数,让它具有新的功能。
在派生类中重新定义此函数时,要求函数名、函数类型、参数个数和类型与基类的虚函数完全相同,并根据需要重新定义函数体。C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数自动成为虚函数,因此,对派生类的虚函数中的virtual说明可以省略。
定义一个指向基类对象的指针变量,并让它获得同一类族中某个对象的地址。
用该指针变量调用虚函数,调用的就是该对象所属类的虚函数。
只有非静态的成员函数才可以说明为虚函数。
构造函数不能说明为虚函数,但是析构函数可以说明为虚函数。
虚函数与函数重载的区别
函数重载处理的是同一层次上的同名函数问题,虚函数处理的是不同派生层次中的同名函数问题。
函数重载要求函数名相同,但函数的参数或类型不同;虚函数处理要求的是不仅函数名相同,而且函数参数和类型也要相同。
虚函数是实现动态多态性的必要条件,而静态多态性是通过函数重载实现的。
动态关联
函数重载和用对象名调用成员函数,在编译时即可确定其调用的函数属于哪个类,其过程称为静态关联。
在运行期间把虚函数和类对象绑定在一起,此过程称为动态关联,这种多态性是动态的多态性。
动态关联实现的三个条件:
基类与派生类定义中要有同名的虚函数;
通过基类对象的指针或者引用访问虚函数;
基类对象的指针或引用有明确的使用对象。
纯虚函数
只声明,不定义的虚函数称为纯虚函数。纯虚函数的作用是为派生类提供一个一致的接口(界面)。它的定义留给派生类来做,派生类根据需要来定义各自的实现。
纯虚函数声明格式:
virtual 函数类型 函数名(参数表) = 0;
一个类可以说明一个或多个纯虚函数。
纯虚函数与函数体为空的虚函数的区别
纯虚函数:
根本没有函数体
所在的抽象类,不能直接进行实例化
空的虚函数:
函数体为空
所在的类可以实例化
共同的特点:
可以派生出新的类
抽象类
带有纯虚函数的类就是抽象类。抽象类的主要作用是为整个类族建立一个公共的接口,使它们能够更有效地发挥多态特性。
抽象类是一个特殊的类,是为了抽象和设计的目的而建立的,它处于继承层次结构的最上层,即只能用作其它类的基类,不能定义对象。
从一个抽象类派生的类必须提供纯虚函数的实现代码或在该派生类中仍将它说明为纯虚函数,否则编译错。
抽象类不能用作参数类型、函数返回类型或显式转换的类型,但可以说明指向抽象类的指针和引用,此指针可以指向它的派生类,实现多态性。
构造函数不能是虚函数,析构函数可以是虚函数。
程序
/* ************************************************************************* @file: main.cpp @date: 2020.12.9 @author: Xiaoxiao @brief: 圆形、矩形、三角形的面积 @blog: https://blog.csdn.net/weixin_43470383/article/details/110880376 ************************************************************************* */ #include<iostream> using namespace std; class Shape // 抽象基类 { public: virtual void printArea() = 0; // 纯虚函数 }; class Circle :public Shape // 定义 Circle 类 { public: Circle(float r) :radius(r) {}; // 定义构造函数 virtual void printArea() // 对虚函数再定义 { cout << "Area of Circle:" << endl << 3.14159 * radius * radius << endl; } private: float radius; }; class Rectangle :public Shape // 定义 Rectangle 类 { public: Rectangle(float w, float h) :width(w), height(h) {}; // 定义构造函数 virtual void printArea() // 对虚函数再定义 { cout << "Area of Rectangle:" << endl << width * height << endl; } private: float width; float height; }; class Triangle :public Shape // 定义 Triangle 类 { public: Triangle(float w, float h) :width(w), height(h) {}; // 定义构造函数 virtual void printArea() // 对虚函数再定义 { cout << "Area of Triangle:" << endl << 0.5 * width * height << endl; } private: float width; float height; }; int main() { Circle circle(4.5); // 建立 Circle 类对象 circle circle.printArea(); // 输出 circle的面积 Rectangle rectangle(2, 6); // 建立 Rectangle 类对象 rectangle rectangle.printArea(); // 输出 rectangle 的面积 Triangle triangle(3, 5); // 建立 Triangle 类对象 triangle.printArea(); // 输出 triangle 的面积 system("pause"); return 0; }
运行结果
输出:
Area of Circle:
63.6172
Area of Rectangle:
12
Area of Triangle:
7.5