基类指针
派生类的一个关键特征就是,派生类指针与基类指针是类型兼容的(type_compatible)。多态就利用了这个简单,但强大、通用的特征,发挥了面向对象方法的全部潜能。
考虑到这个指针兼容的特征,我们将重写前面章节的矩形与三角形的例子:
// pointers to base class #includeusing namespace std; class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } }; class CRectangle: public CPolygon { public: int area () { return (width * height); } }; class CTriangle: public CPolygon { public: int area () { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; CPolygon * ppoly1 = ▭ CPolygon * ppoly2 = &trgl; ppoly1->set_values (4,5); ppoly2->set_values (4,5); cout << rect.area() << endl; cout << trgl.area() << endl; return 0; }
输出:20 10
在函数main中,我们创建了两个指向类CPolygon对象的指针(ppoly1和ppoly2)。然后用rect和trg1的引用对其赋值,这两个对象的类派生自CPolygon,因此两者都是有效赋值操作。
用*ppoly1和*ppoly2代替rect和trg1的唯一限制是,*ppoly1和*ppoly2是CPolygon*类型,因此我们仅能利用这些指针操作CRectangle和CTriangle继承自CPolygon的成员。由于这个原因,当我们在程序最后调用area()成员时,必须直接用对象rect和trg1,而不是用指针*ppoly1和*ppoly2。
为了通过类CPolygon的指针调用area(),这个成员要在类CPolygon中声明,而不仅仅是在派生类中声明。但问题是CRectangle和CTriangle实现了不同版本的area(),因此我们不能在基类中实现它。这时虚成员就派上了用场:
虚成员
一个类的成员可以被其派生类重定义,则称其为虚拟成员。为了声明一个类的虚成员,我们必须在其声明前加virtual关键字:
// virtual members #includeusing namespace std; class CPolygon { protected: int width, height; public: void set_values (int a, int b) { width=a; height=b; } virtual int area () { return (0); } }; class CRectangle: public CPolygon { public: int area () { return (width * height); } }; class CTriangle: public CPolygon { public: int area () { return (width * height / 2); } }; int main () { CRectangle rect; CTriangle trgl; CPolygon poly; CPolygon * ppoly1 = ▭ CPolygon * ppoly2 = &trgl; CPolygon * ppoly3 = &poly; ppoly1->set_values (4,5); ppoly2->set_values (4,5); ppoly3->set_values (4,5); cout << ppoly1.>area() << endl; cout << ppoly2.>area() << endl; cout << ppoly3.>area() << endl; return 0; }
输出:20 10 0
现在这三个类(CPolygon,CRectangle和CTriangle)拥有相同的成员:width,height,set_values()和area()。
因为在派生类中被重新定义,成员函数area()在基类中被定义为虚函数,。你可以验证一下,如果去掉类CPolygon 中area()声明的virtual关键字,然后运行程序,结果将是三个多边形都为0,而不是20,10和0。那是因为由于调用是通过CPolygon*指针,在所有情况下CPolygon::area()都将被调用,而不是分别调用各个对象的area()函数((CRectangle::area(),CTriangle::area() 和 CPolygon::area())。
因此,virtual关键字的作用是允许通过指针恰当的调用派生类中与基类中同名的成员,更准确地说,如同上面的例子,此指针是基类类型,但指向派生类对象的指针。
一个声明或继承了虚函数的类称为多态类。
虽然有虚拟性,但我们仍然可以声明CPolygon类型的对象,并且调用其area()函数,总是返回0。
未完待续。。。
原文: