Cplusplus 简明教程
Polymorphism in C++
polymorphism 一词意味着有多种形式。通常,多态性发生在有类层次结构并且类通过继承相关的情况时。
The word polymorphism means having many forms. Typically, polymorphism occurs when there is a hierarchy of classes and they are related by inheritance.
C++ 多态性意味着成员函数的调用会根据调用该函数的对象的类型导致执行不同的函数。
C++ polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.
考虑以下示例,其中一个基类是由其他两个类派生的 −
Consider the following example where a base class has been derived by other two classes −
#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;
}
编译并执行上述代码后,将产生以下结果 −
When the above code is compiled and executed, it produces the following result −
Parent class area :70
Parent class area :50
输出有误的原因是编译器一次按基类中定义的版本设置 area() 函数的调用。这称作函数调用的 static resolution ,或 static linkage - 在执行程序之前修复函数调用。由于在程序编译期间设置 area() 函数,所以有时也称作 early binding 。
The reason for the incorrect output is that the call of the function area() is being set once by the compiler as the version defined in the base class. This is called static resolution of the function call, or static linkage - the function call is fixed before the program is executed. This is also sometimes called early binding because the area() function is set during the compilation of the program.
不过,现在让我们对程序做些微小的修改,并在 Shape 类中在 area() 声明之前加上关键字 virtual ,使其类似于下文所述 −
But now, let’s make a slight modification in our program and precede the declaration of area() in the Shape class with the keyword virtual so that it looks like this −
#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;
}
完成此微小修改后,在编译并执行前一个示例代码时,会得到以下结果 −
After this slight modification, when the previous example code is compiled and executed, it produces the following result −
Rectangle class area :70
Triangle class area :25
这次,编译器查看指针的实际内容,而不是它的类型。因此,因为 *shape 中存储了 tri 和 rec 类的对象地址,所以调用了相应的 area() 函数。
This time, the compiler looks at the contents of the pointer instead of it’s type. Hence, since addresses of objects of tri and rec classes are stored in *shape the respective area() function is called.
如您所见,每个子类对函数 area() 具有单独的实现。这就是一般使用 polymorphism 的方式。您有不同类别的函数拥有相同名称,甚至相同参数,但实现不同。
As you can see, each of the child classes has a separate implementation for the function area(). This is how polymorphism is generally used. You have different classes with a function of the same name, and even the same parameters, but with different implementations.
Virtual Function
virtual 函数是在基类中声明并使用关键字 virtual 声明的函数。在基类中定义一个虚函数,并在派生类中使用另一个版本表示着我们不希望为该函数建立静态链接。
A virtual function is a function in a base class that is declared using the keyword virtual. Defining in a base class a virtual function, with another version in a derived class, signals to the compiler that we don’t want static linkage for this function.
在程序的任意给定点,我们希望根据为其调用函数的对象类型来选择要调用的函数。这种操作称为 dynamic linkage 或 late binding 。
What we do want is the selection of the function to be called at any given point in the program to be based on the kind of object for which it is called. This sort of operation is referred to as dynamic linkage, or late binding.
Pure Virtual Functions
你可能希望在基类中包含一个虚函数,以便它可以在派生类中重新定义,以适合该类的对象,但基类中没有你能给函数的更有意义的定义。
It is possible that you want to include a virtual function in a base class so that it may be redefined in a derived class to suit the objects of that class, but that there is no meaningful definition you could give for the function in the base class.
我们可以在基类中将虚函数area()更改为以下内容−
We can change the virtual function area() in the base class to the following −
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告诉编译器函数没有主体,并且上面的虚函数将被调用 pure virtual function 。
The = 0 tells the compiler that the function has no body and above virtual function will be called pure virtual function.