得到任何深入本章之前,你应该有指针和类继承的一个正确的认识。如果你真的不知道的任何下列用语的含义,你应该检查表明部分:
声明: 解释了: 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 = ▭
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
(命名
ppoly1
和
ppoly2
)。这些被分配的地址
rect
和
trgl
分别,这是类型的对象
Rectangle
和
Triangle
。这样的分配是有效的,因为这两个
Rectangle
和
Triangle
从派生类
Polygon
。
解引用
ppoly1
和
ppoly2
(同
*ppoly1
和
*ppoly2
)是有效的,使我们能够访问他们的尖锐物体的成员。例如,下面的两个语句是在前面的例子中相当于:
1
2
ppoly1->set_values (4,5);
rect.set_values (4,5);
但由于类型
ppoly1
和
ppoly2
是指针
Polygon
(而不是指针到
Rectangle
也不指针
Triangle
),只有部件从继承
Polygon
可以被访问,而不是那些派生类的
Rectangle
和
Triangle
。这就是为什么上面的程序访问
area
使用两个对象的成员
rect
和
trgl
直接,而不是指针; 指针到基类不能访问
area
成员。
部件
area
可能已经与指针访问
Polygon
,如果
area
是的一个成员
Polygon
,而不是它的派生类的一员,但问题是,
Rectangle
和
Triangle
实施的不同版本
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 = ▭
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
在本实施例中,所有三个类(
Polygon
,
Rectangle
和
Triangle
),由于具有相同的部件:
width
,
height
,和功能
set_values
和
area
。
成员函数
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 = ▭
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 = ▭
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
”,但分配的对象已宣布有直接派生类类型(
Rectangle
和
Triangle
)。