多态性

得到任何深入本章之前,你应该有指针和类继承的一个正确的认识。如果你真的不知道的任何下列用语的含义,你应该检查表明部分:

声明:解释了:
int A::b(int c) { }
a->b数据结构
class A: public B {};友谊和继承

指针的基类

其中一个类继承的主要特点是一个指向派生类的类型是兼容的指针其基类。 多态性是接受这个简单但功能强大和灵活的功能优势的艺术。

对矩形和三角形类的实例可以使用指针利用这个特性考虑被改写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 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 () {
  Rectangle rect;
  Triangle trgl;
  Polygon * ppoly1 = &rect;
  Polygon * ppoly2 = &trgl;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  cout << rect.area() << '\n';
  cout << trgl.area() << '\n';
  return 0;
}
20
10


函数 main声明了两个指针 Polygon(命名 ppoly1ppoly2)。这些被分配的地址 recttrgl分别,这是类型的对象 RectangleTriangle。这样的分配是有效的,因为这两个 RectangleTriangle从派生类 Polygon

解引用 ppoly1ppoly2(同 *ppoly1*ppoly2)是有效的,使我们能够访问他们的尖锐物体的成员。例如,下面的两个语句是在前面的例子中相当于:

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


但由于类型 ppoly1ppoly2是指针 Polygon(而不是指针到 Rectangle也不指针 Triangle),只有部件从继承 Polygon可以被访问,而不是那些派生类的 RectangleTriangle。这就是为什么上面的程序访问 area使用两个对象的成员 recttrgl直接,而不是指针; 指针到基类不能访问 area成员。

部件 area可能已经与指针访问 Polygon,如果 area是的一个成员 Polygon,而不是它的派生类的一员,但问题是, RectangleTriangle实施的不同版本 area,因此没有可能在基类来实现一个单一的共同版本。

虚拟成员

虚拟成员是可以在派生类中被重新定义,同时通过引用保留其调用属性成员函数。一个函数成为虚拟的语法与先于它的声明 virtual关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 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 = &rect;
  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;
}
20
10
0


在本实施例中,所有三个类( PolygonRectangleTriangle),由于具有相同的部件: widthheight,和功能 set_valuesarea

成员函数 area已被宣布为 virtual在基类,因为它是在每一个派生类的后来重新定义。非虚拟部件,也可以在子类中重新定义,但派生类的非虚拟部件不能通过基类的引用来访问:即,如果 virtual是从声明除去 area在上面的例子中,所有三个调用 area将返回零,因为在所有情况下,所述基类的版本会被称为代替。

因此,本质上,有什么 virtual关键字确实是允许使用相同的名称为一体,在基类派生类的一个成员,以从一个指针适当地调用,并且更精确地,当指针的类型是指向基被指向派生类的一个对象,如在上述实施例类。

声明或继承的虚拟函数的类被称为 多态类

需要注意的是,尽管其成员之一的虚拟性, Polygon是一个普通类,其中甚至对象实例化( poly),有自己的成员的定义 area总是返回0。

抽象基类

抽象基类的东西非常类似于 Polygon类先前示例中所示。它们只能用作基类,并且因此允许有虚拟成员函数不定义(称为纯虚函数)类。语法是取代他们的定义 =0(一个等号和一个零):

一个抽象基 Polygon类可以是这样的:

1
2
3
4
5
6
7
8
9
// abstract class CPolygon
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不能用于声明对象像:

 
Polygon mypolygon;   // not working if Polygon is abstract base class 
 


但是,一个 抽象基类也不是完全没用的。它可用于创建指向它,并采取其所有多态型的能力的优点。例如,下面的指针声明将是有效的:

1
2
Polygon * ppoly1;
Polygon * ppoly2;
 


而实际上可以指向派生(非抽象)类的对象时取消引用。这里是整个例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 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 (void) =0;
};

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 = &rect;
  Polygon * ppoly2 = &trgl;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  cout << ppoly1->area() << '\n';
  cout << ppoly2->area() << '\n';
  return 0;
}
20
10


在这个例子中,不同但相关的类型的对象是指使用一种独特类型的指针(的 Polygon*)和适当的成员函数被调用每次,只是因为它们是虚拟的。这可以是在某些情况下非常有用。例如,甚至有可能对抽象基类的一个成员 Polygon使用特殊的指针 this来访问适当的虚拟部件,即使 Polygon本身具有该功能没有实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 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 = &rect;
  Polygon * ppoly2 = &trgl;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly1->printarea();
  ppoly2->printarea();
  return 0;
}
20
10


虚拟成员和抽象类授予C ++多态特性,面向对象的项目中非常有用。当然,上面的例子是非常简单的用例,但这些特征可以被应用到对象的数组或动态分配对象。

这里是结合一些在最近的章节,如动态存储器,构造函数初始化和多态性的功能的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 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;
}
20
10


注意, ppoly指针:

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


声明作为类型的“指针 Polygon”,但分配的对象已宣布有直接派生类类型( RectangleTriangle)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值