(翻译)C++ 多态机制

                            

 原文来自点击打开链接

www.cplusplus.com使用google搜索C++polymorphic显示的第一个网页便是该网页.

ps(www.cplusplus.com是我平时最为常用的C++文档网站,强烈推荐)


  C++ 多态机制

 


         在更深入的了解本章节前,你需要对于指针与类的继承有初步的理解.如果你不是很确定是否理解以下的表达式,你需要复习下列的章节

Statement:

Explained in:

int A::b(int c) { }

Classes

a->b

Data structures

class A: public B {};

友元与继承

 

 

 

  指向基类的指针

 

  关于类的继承,有一个特性特别的关键,那就是继承类允许具有可相容其基类对象的指针,多态正是基于这一简单但是有效并且多用特性的艺术.

         以下例子,真是基于以上特性,利用指针来完成可复写的三角与矩形类.

 

 

/ /pointers to base class
#include <iostream>
using namespace std;
 
class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      {width=a; height=b; }
};
 
class Rectangle: public Polygon {
  public:
    int area()
      {return width*height; }
};
 
class Triangle: public Polygon {
  public:
    int area()
      {return width*height/2; }
};
 
int main () {
  Rectanglerect;
 Triangle trgl;
 Polygon * ppoly1 = ▭
 Polygon * ppoly2 = &trgl;
 ppoly1->set_values (4,5);
 ppoly2->set_values (4,5);
  cout<< rect.area() << '\n';
  cout<< trgl.area() << '\n';
  return 0;
}
 

 返回结果

 

 

 

函数main中,声明两个指向 Polygon 的指针(命名为ppoly1 和 ppoly2),他们被分别用于指向 继承同一基类的rectangle 类tect与Traiang类trgl.因此以下两个表达式都是等价的

 

ppoly1->set_values (4,5);
rect.set_values (4,5);
 


 

         然而因为ppoly1与ppoly2是指向Polyon,而非指向Rectangle与Triangle.因此只有继承自Polygon类的成员允许被访问.而来自Retangle与Traingle不许被访问.这就是为什么我在这里使用类rect与trgl而不是指针(ppoly1与ppoly2)来访问area函数,指向基类的指针是无法访问成员函数area的.

         只有当area是基类Polygon的成员,而非其继承类的成员时,使用指向基类的指针允许访问area成员.但是问题在于Retangle与Triangle具有两个不同版本的area函数,因此不具有一个单一的通用的版本能够在基类中被运用.

虚函数

虚函数是能够在继承类中被重定义的成员函数,因此其可以保护通过引用来访问(类的)特性(的行为).虚函数使用关键字virtual来定义.

// virtual members
#include <iostream>
using namespace std;
 
class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area ()
      { return 0; }
};
 
class Rectangle: public Polygon {
  public:
    int area ()
      { return width * height; }
};
 
class Triangle: public Polygon {
  public:
    int area ()
      { return (width * height / 2); }
};
 
int main () {
  Rectangle rect;
  Triangle trgl;
  Polygon poly;
  Polygon * ppoly1 = ▭
  Polygon * ppoly2 = &trgl;
  Polygon * ppoly3 = &poly;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly3->set_values (4,5);
  cout << ppoly1->area() << '\n';
  cout << ppoly2->area() << '\n';
  cout << ppoly3->area() << '\n';
  return 0;
}


在上述的例子中,使用了三个类(Polygon,Rectangle,Triangle)具有相同的成员:width,heigh与相同的函数set_value area.

成员函数area在继承类中被声明成虚函数.非虚函数也在继承类中被声明,然而这些非虚函数,无法通过基类的引用被调用,比如,如果area函数关键字virtual被移除,那么在上述的例子中,三个对area的访问将返回0,因为在上述的例子中,基类的函数版本将会在本次的访问中被调用.

因此,本质上,关键字virtual被用于使用以允许指针访问成员函数,该继承类函数与与基类同名.更精确的说在上述例子中,上述类型的指针式指向继承类的基类指针.

 

一个类能共被声明或者继承一个虚函数是被称作是多态类.

尽管具有一个虚函数,Polygon依旧是一个允许被实例化的普通类(poly),本身的成员函数area依旧可以返回0.

 

抽象基类

     抽象基类与此前的Polygon基类类似,其是只被允许被当做基类来使用.因此其允许拥有不需要定义的函数(纯虚函数).

      以下为一个具体的纯虚类Polygon

 

class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area () =0;
};
 

 

      注意在这里area,没有被定义,相反被=0替代,这使得该函数被定义为纯虚函数.包含纯虚函数的类被称作是抽象基类.

          
Polygon mypolygon;   // 由于Polygon是抽象基类因此这里无法工作       
    但是抽象基类并非是无用的.它能共用于定义指向抽象基类的指针,其能共使用基类的多态属性.


2

Polygon * ppoly1;

Polygon * ppoly2;

 

 

 

该类指向继承类的指针是可以被解引用的.

     

 

class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area () =0;
};
 

         在上述的例子中,两个不同却又相关的类型使用相同的指针(Polygon*),同时每一次(对函数)访问都是适当的.因为该函数是虚函数.他们在一些的环境下都是可用的,下面是一个例子,

 

某个抽象基类Polygon的成员函数可以被指针this访问虚函数,及时Polygon没有被实例化.

// pure virtual members can be called
// from the abstract base class
#include <iostream>
using namespace std;
 
class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area() =0;
    void printarea()
      { cout << this->area() << '\n'; }
};
 
class Rectangle: public Polygon {
  public:
    int area (void)
      { return (width * height); }
};
 
class Triangle: public Polygon {
  public:
    int area (void)
      { return (width * height / 2); }
};
 
int main () {
  Rectangle rect;
  Triangle trgl;
  Polygon * ppoly1 = ▭
  Polygon * ppoly2 = &trgl;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  return 0;
}
 


 

         虚函数与抽象基类在C++的多态特性中具有重大的价值,几乎可以说是最有价值的下面的.当然上述的例子非常简单,但是上述的特性在类数组或者是动态分配数组中依旧适用.

         下述的例子包含前几章节的某些特性,包括动态内存,构造器,多态

 

// dynamic allocation and polymorphism
#include <iostream>
using namespace std;
 
class Polygon {
  protected:
    int width, height;
  public:
    Polygon (int a, int b) : width(a), height(b) {}
    virtual int area (void) =0;
    void printarea()
      { cout << this->area() << '\n'; }
};
 
class Rectangle: public Polygon {
  public:
    Rectangle(int a,int b) : Polygon(a,b) {}
    int area()
      { return width*height; }
};
 
class Triangle: public Polygon {
  public:
    Triangle(int a,int b) : Polygon(a,b) {}
    int area()
      { return width*height/2; }
};
 
int main () {
  Polygon * ppoly1 = new Rectangle (4,5);
  Polygon * ppoly2 = new Triangle (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  delete ppoly1;
  delete ppoly2;
  return 0;
}


 

 

上面的ppoly指针:

olygon * ppoly1 = new Rectangle (4,5);
Polygon * ppoly2 = new Triangle (4,5);


是被声明成Polygon类型,但是依旧动态构造成指向继承类的指针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值