原创 C++学习之路(九) 多态

2014-2-17 16:01 1959 16 17 分类: 软件与OS 文集: C++ 学习之路

多态 (Polymorphism)

1.基类的指针(Pointers to base class)

     继承的好处之一是一个指向子类(derived class)的指针与一个指向基类(base class)

的指针是 type-compatible 的。本节就是重点介绍如何利用 C++的这一重要特性。例如,

我们将结合 C++的这个功能,重写前面小节中关于长方形 rectangle 和三角形 triangle

的程序:

// pointers to base class

#include

class CPolygon      //定义一个多边形的类

{

protected:

int width, height;

public:

void set_values (int a, int b)

 {

width=a; height=b;

}

};

 

class CRectangle: public CPolygon //定义一个继承自CPolygon 的 class CRectangle

{

public:

int area (void)

{

return (width * height);

}

};

class CTriangle: public CPolygon //定义一个继承自CPolygon 的 class CTriangle

 

{

public:

int area (void)

{

return (width * height / 2);

}

};

int main ()

{

CRectangle rect;

CTriangle trgl;

CPolygon * ppoly1 = ▭   //定义CPolygon的指针分别指向rect 和 trg1

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 中定义了两个指向 class CPolygon 的对象的指针,即 *ppoly1 和

*ppoly2。 它们被赋值为 rect 和 trgl 的地址,因为 rect 和 trgl 是 CPolygon 的子

类的对象,因此这种赋值是有效的。

     使用*ppoly1 和 *ppoly2 取代 rect 和 trgl 的唯一限制是*ppoly1 和 *ppoly2 是

CPolygon* 类型的,因此我们只能够引用 CRectangle 和 CTriangle 从基类 CPolygon

中继承的成员。正是由于这个原因,我们不能够使用*ppoly1 和 *ppoly2 来调用成员函

数 area(),而只能使用 rect 和 trgl 来调用这个函数。

要想使 CPolygon 的指针承认 area()为合法成员函数,必须在基类中声明它,而不能只

在子类进行声明。

2.虚拟成员(Virtual members)

      如果想在基类中定义一个成员留待子类中进行细化,我们必须在它前面加关键字

virtual ,以便可以使用指针对指向相应的对象进行操作。

请看一下例子:

// virtual members

#include

class CPolygon

{

protected:

int width, height;

public:

void set_values (int a, int b)

{

width=a;

height=b;

}

virtual int area (void)

{

 return(0);

}

};

class CRectangle: public CPolygon

{

public:

int area (void)

{ return (width *height); }

};

 

class CTriangle: public CPolygon

{

public:

int area (void)

{

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() 被定义为 virtual 是因为它后来在子类中被细化了。你可

以做一个试验,如果

在代码种去掉这个关键字(virtual),然后再执行这个程序,三个多边形的面积计算结果

都将是 0 而不是 20,10,0。这是因为没有了关键字 virtual ,程序执行不再根据实际对

象的不用而调用相应 area() 函数(即分别为 CRectangle::area(), CTriangle::area()

和 CPolygon::area()),取而代之,程序将全部调用 CPolygon::area(),因为这些调用

是通过 CPolygon 类型的指针进行的。

因此,关键字 virtual 的作用就是在当使用基类的指针的时候,使子类中与基类同名的

成员在适当的时候被调用,如前面例子中所示。

注意,虽然本身被定义为虚拟类型,我们还是可以声明一个 CPolygon 类型的对象并调

用它的 area() 函数,它将返回 0 ,如前面例子结果所示。

 

3.抽象基类(Abstract base classes)

    基本的抽象类与我们前面例子中的类 CPolygon 非常相似,唯一的区别是在我们前面的

例子中,我们已经为类 CPolygon 的对象(例如对象 poly)定义了一个有效地 area()函

数,而在一个抽象类(abstract base class)中,我们可以对它不定义,而简单得在函

数声明后面写 =0 (等于 0)。

类 CPolygon 可以写成这样:

// abstract class CPolygon

class CPolygon

{

protected:

int width, height;

public:

void set_values (int a, int b) {

width=a;

height=b;

}

virtual int area (void) =0;

};

注意我们是如何在 virtual int area (void)加=0 来代替函数的具体实现的。这种函

数被称为纯虚拟函数(pure virtual function),而所有包含纯虚拟函数的类被称为抽

象基类(abstract base classes)。

抽象基类的最大不同是它不能够有实例(对象),但我们可以定义指向它的指针。因此,

像这样的声明:

CPolygon poly;

对于前面定义的抽象基类是不合法的。

然而,指针:

CPolygon * ppoly1;

CPolygon * ppoly2

是完全合法的。这是因为该类包含的纯虚拟函数(pure virtual function) 是没有被实

现的,而又不可能生成一个不包含它的所有成员定义的对象。然而,因为这个函数在其

子类中被完整的定义了,所以生成一个指向其子类的对象的指针是完全合法的。

下面是完整的例子:

// virtual members

#include

class CPolygon     //定义抽象基类

{

protected:

int width, height;

public:

void set_values (int a, int b)

{

width=a;

height=b;

}

virtual int area (void) =0;

};

class CRectangle: public CPolygon

{

public:

int area (void) { return (width *

height);

}

};

class CTriangle: public CPolygon

{

public:

int area (void)

{

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 << ppoly1->area() << endl;

cout << ppoly2->area() << endl;

return 0;

}

结果:

20

10

再看一遍这段程序,你会发现我们可以用同一种类型的指针(CPolygon*)指向不同类的对

象,至一点非常有用。 想象一下,现在我们可以写一个 CPolygon 的成员函数,使得它

可以将函数 area()的结果打印到屏幕上,而不必考虑具体是为哪一个子类。

// virtual members

#include

class CPolygon

{

protected:

int width, height;

public:

void set_values (int a, int b)

{

width=a;

height=b;

}

virtual int area (void) =0;

void printarea (void)     //在抽象基类中声明printarea函数  便于后面的调用

{

cout << this->area() << endl;

}

};

class CRectangle: public CPolygon

{

public:

int area (void)

{

return (width *height);

}

};

class CTriangle: public CPolygon

{

public:

int area (void) {

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);

ppoly1->printarea();

ppoly2->printarea();

return 0;

}

结果:

20

10

 

记住,this 代表代码正在被执行的这一个对象的指针。

抽象类和虚拟成员赋予了 C++ 多态(polymorphic)的特征,使得面向对象的编程

object-oriented programming 成为一个有用的工具。这里只是展示了这些功能最简单

的用途。想象一下如果在对象数组或动态分配的对象上使用这些功能,将会节省多少麻

烦。

文章评论1条评论)

登录后参与讨论

用户1842909 2015-8-2 16:33

谢谢分享

用户1836130 2015-7-9 22:30

东西真不错,谢谢博主分享

用户1271441 2015-6-6 10:16

谢谢分享

john_xjm_149062208 2015-4-30 09:05

不错,拍的还是蛮清楚的。谢谢分享

用户373711 2014-2-22 15:27

多态性通过抽象类和虚函数实现基类指针和子类对象的赋值兼容性!
相关推荐阅读
用户420622 2014-02-17 15:45
C++ 学习之路(五) 类的构成
类(Classes)       类(class)是一种将数据和函数组织在同一个结构里的逻辑方法。定义类的关键字为 class ,其功能与 C 语言中的 struct 类似,不同之处是 c...
用户420622 2014-02-15 15:43
C++ 学习之路(八) 类之间的继承
类之间的继承     类的一个重要特征是继承,这使得我们可以基于一个类生成另一个类的对象,以便使后 者拥有前者的某些成员,再加上它自己的一些成员。例如,假设我们要声明一系列类型 的多边...
用户420622 2014-02-15 09:32
C++学习之路 (七) 类之间的关系
类之间的关系(Relationships between classes)   1.友元函数(Friend functions)      前面的章节中我们已经看到了对 class 的不同成员存...
用户420622 2014-02-14 10:01
C++学习之路(二)控制台交互
四.控制台交互(Communication through console) 在 C++的 iostream 函数库中,一个程序的标准输入输出操作依靠两种数据流:cin 给输入使用和 cout...
用户420622 2014-02-14 10:00
C++ 学习之路(一)
前言:    大家好,我是来自南京的一名大四学生,专业是电子信息工程。最近在学习Qt的过程中回顾了C++的相关知识,感觉收获很多。这是我第一次发文章,在文章中我将重点关注C++中与C的异同之处...
我要评论
1
16
关闭 站长推荐上一条 /2 下一条