C++ 多态性
单词 多态性 意味着具有多种形式。通常,当存在类的层次结构并且它们通过继承相关联时,就会发生多态性。
C++的多态性意味着对成员函数的调用会导致根据调用该函数的对象类型而执行不同的函数。
考虑以下示例,其中一个基类已被其他两个类派生:
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0){
width = a;
height = b;
}
int area() {
cout << "Parent class area :" << width * height << endl;
return width * height;
}
};
class Rectangle: public Shape {
public:
Rectangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Rectangle class area :" << width * height << endl;
return (width * height);
}
};
class Triangle: public Shape {
public:
Triangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Triangle class area :" << (width * height)/2 << endl;
return (width * height / 2);
}
};
// Main function for the program
int main() {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// store the address of Rectangle
shape = &rec;
// call rectangle area.
shape->area();
// store the address of Triangle
shape = &tri;
// call triangle area.
shape->area();
return 0;
}
当上面的代码被编译并执行时,它会产生以下结果 −
Parent class area :70
Parent class area :50
不正确的输出的原因是,编译器将函数area()的调用设置为基类中定义的版本。这被称为静态解析或静态链接 – 即在程序执行之前,函数调用被固定下来。有时也称之为早期绑定,因为area()函数在编译程序时设置。
但是现在,让我们对程序进行轻微修改,在Shape类的声明之前加上关键字virtual,代码如下:
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a = 0, int b = 0){
width = a;
height = b;
}
virtual int area() {
cout << "Parent class area :" << width * height << endl;
return width * height;
}
};
class Rectangle: public Shape {
public:
Rectangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Rectangle class area :" << width * height << endl;
return (width * height);
}
};
class Triangle: public Shape {
public:
Triangle( int a = 0, int b = 0):Shape(a, b) { }
int area () {
cout << "Triangle class area :" << (width * height)/2 << endl;
return (width * height / 2);
}
};
// Main function for the program
int main() {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// store the address of Rectangle
shape = &rec;
// call rectangle area.
shape->area();
// store the address of Triangle
shape = &tri;
// call triangle area.
shape->area();
return 0;
}
在进行了这个轻微修改之后,当之前的示例代码被编译和执行时,会产生以下结果−
Rectangle class area :70
Triangle class area :25
这次,编译器查看指针的内容而不是它的类型。因此,由于三角形和矩形类的对象的地址存储在*shape中,相应的area()函数被调用。
正如你所看到的,每个子类都有area()函数的不同实现。这就是多态性的一般用法。你有不同的类,有相同名称的函数,甚至相同的参数,但是有不同的实现。
虚函数
虚函数是一个在基类中声明的使用关键字virtual的函数。在基类中定义一个虚函数,并在派生类中定义另一个版本,告诉编译器我们不希望这个函数使用静态链接。
我们希望的是,在程序的任何给定点调用函数的选择是基于调用它的对象的类型。这种操作被称为动态链接或晚期绑定。
纯虚函数
有时候,你可能希望在基类中包含一个虚函数,以便在派生类中重新定义,以适应该类的对象,但是在基类中无法给出有意义的定义。
我们可以将基类中的虚函数area()更改为以下内容 –
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) {
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
= 0告诉编译器该函数没有函数体,上面的虚函数将被称为纯虚函数。