1.多态性的概念
多态性:向不同的对象发送同一个消息,不同的对象在接受时,会产生不同的行为
支持多态:面向对象:C++、java
不支持多态:基于对象的:VB、Ada
多态的两种情况
静态多态:在程序编译时就能决定调用哪个函数
实现:函数的重载(包含运算符重载)
动态多态:在程序运行过程中才能决定调用的对象成员
实现:虚函数(virtual function)
2.虚函数
构造函数不能为虚函数。
基类的析构函数应该为虚函数。
友元函数不能为虚,因为友元函数不是类成员,只有类成员才能是虚函数。
如果派生类没有重定义函数,则会使用基类版本。
重新定义继承的方法若和基类的方法不同(协变除外),会将基类方法隐藏;如果基类声明方法被重载,则派生类也需要对重载的方法重新定义,否则调用的还是基类的方法。
声明方法:virtual 函数类型 函数名(){}
如下面程序,
#include<iostream>
using namespace std;
class point{
protected:
float x;
float y;
public:
point(int a,int b){
x=a;
y=b;
}
void show();
};
void point::show(){
cout<<x*y<<endl;
}
class line:public point{
protected:
float z;
public:
line(int a,int b,int c):point(a,b){
z=c;
}
void show();
};
void line::show(){
cout<<x*y*z<<endl;
}
int main(){
point s1(2,2);
line s2(2,2,2);
point *p;
p=&s1;
p->show();
p=&s2;
p->show();
return 0;
}
4
4
--------------------------------
Process exited after 0.206 seconds with return value 0
请按任意键继续. . .
当定义一个point类的指针对象后,将一个line类对象赋值给它,
当后者调用show函数时,调用的却是基类的show函数,
那么,如何解决这种问题,使p也能够调用子类的同名函数呢?
这里就用到了虚函数!
#include<iostream>
using namespace std;
class point{
protected:
float x;
float y;
public:
point(int a,int b){
x=a;
y=b;
}
virtual void show(); //此处将show函数定义为了虚函数
};
void point::show(){
cout<<x*y<<endl;
}
class line:public point{
protected:
float z;
public:
line(int a,int b,int c):point(a,b){
z=c;
}
void show();
};
void line::show(){
cout<<x*y*z<<endl;
}
int main(){
point s1(2,2);
line s2(2,2,2);
point *p;
p=&s1;
p->show();
p=&s2;
p->show();
return 0;
}
4
8
--------------------------------
Process exited after 0.2267 seconds with return value 0
请按任意键继续. . .
从上面可以看到,当show函数被声明为虚函数后,当point类指针p被line类对象赋值后,就可调用其show函数,而不是基类point的show函数!
3.纯虚函数
非基类本身需求,而是考虑派生类需要而定义的空函数,其函数内容将在派生类中定义
定义方法:
声明一个虚函数,并将其赋值为0
格式: virtual 函数类型 函数名(参数列表) =0;
例:virtual float area() const =0;
几点说明:
纯虚函数没有函数体,也就没有“{ }”;
函数后面的“=0”不是表示返回值为0,而是纯虚函数的定义方式;
纯虚函数是用语句声明的,后面必须有分号结尾
纯虚函数不能被调用。只有在派生类中定义后,才能够被调用
纯虚函数的作用:确立多态性的起点
4.抽象类
不用来定义对象而只作为一种基本类型用作继承的类
抽象类(abstract class)或抽象基类
凡是包含纯虚函数的类都是抽象类
纯虚函数不能被调用,因而包含纯虚函数的类,无法建立对应的对象
如果一个派生类,未能对其基类中所有的纯虚函数进行定义,则该派生类仍然是抽象类。
#include <iostream>
#define PI 3.14
using namespace std;
class Calculate{ //此类为抽象基类,只定义虚函数确定方向,函数实现由子类完成
virtual double getPerimeter() = 0;
virtual double getArea() = 0;
virtual double getCircleArea() = 0;
};
class BaseData: public Calculate{
private:
double bottom;
double height;
double radius;
public:
BaseData(double a, double b, double c):bottom(a),height(b),radius(c){}
double getPerimeter(){
return 2 * (bottom + height);
}
double getArea(){
return bottom * height;
}
double getCircleArea(){
return PI * radius * radius;
}
};
int main(){
double a, b, c;
cin>>a>>b>>c;
BaseData* baseData = new BaseData(a,b,c);
cout<<baseData->getPerimeter()<<endl;
cout<<baseData->getArea()<<endl;
cout<<baseData->getCircleArea()<<endl;
delete baseData;
return 0;
}