Contents

假设我们有一个父类A,一个子类B,如果我们创建一个B的数组,我们能这样用吗?

1
A* barray = new B[10];

写段代码在Visual Studio中来试试吧:)


 

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <assert.h>

using namespace std;
class B;
class A
{
public:
A();
~A();
int aa;
};

class B:public A
{
public:
B();
~B();
int bb;
};

A::A()
{
cout<<"A"<<" ";
aa=1;
}

A::~A()
{
cout<<"~A"<<" ";
aa=-1;
}

B::B()
{
cout<<"B"<<" ";
bb=2;
}

B::~B()
{
cout<<"~B"<<" ";

bb=-2;
}

int main(int argc, char* argv[])
{
cout<<"size of A: "<<sizeof(A)<<endl;
cout<<"size of B: "<<sizeof(B)<<endl;
A* aarray = new B[10];

cout<<endl<<endl<<"aa value of A* is:"<<endl;
for (int i = 0; i < 10; i++)
{
cout<<aarray[i].aa<<", ";
}
cout<<endl;

B* baaray = (B*)aarray;
cout<<endl<<"aa value of B* is:"<<endl;
for (int i = 0; i < 10; i++)
{
cout<<baaray[i].aa<<", ";
}
cout<<endl<<endl;

delete[] aarray;
cout<<endl<<endl<<"After delete[]"<<endl;

cout<<endl<<"aa value of A* is:"<<endl;
for (int i = 0; i < 10; i++)
{
cout<<aarray[i].aa<<", ";
}
cout<<endl;
baaray = (B*)aarray;
cout<<endl<<"aa value of B* is:"<<endl;
for (int i = 0; i < 10; i++)
{
cout<<baaray[i].aa<<", ";
}
return 0;
}

 


我们可以看到输出的结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
size of A: 4
size of B: 8
A B A B A B A B A B A B A B A B A B A B

aa value of A* is:
1, 2, 1, 2, 1, 2, 1, 2, 1, 2,

aa value of B* is:
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

~A ~A ~A ~A ~A ~A ~A ~A ~A ~A

After delete[]

aa value of A* is:
4408224, -1, -1, -1, -1, -1, -1, -1, -1, -1,

aa value of B* is:
4408224, -1, -1, -1, -1, 1, 1, 1, 1, 1,

说明尽管我们创建时用的是new B,但是因为声明的是A*,所以被认为是一个A的数组,按照A的大小来操作,所以可以看到成员变量aa的值是不对的。而且最后析构的时候只调用了A的析构函数,说明这个数组在delete的时候也是有问题的。


 


如果我们把A的析构函数加上virtual,可以得到如下的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
size of A: 8
size of B: 12
A B A B A B A B A B A B A B A B A B A B

aa value of A* is:
1, 668240, 2, 1, 668240, 2, 1, 668240, 2, 1,

aa value of B* is:
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,

~B ~A ~B ~A ~B ~A ~B ~A ~B ~A ~B ~A ~B ~A ~B ~A ~B ~A ~B ~A

After delete[]

aa value of A* is:
-1, 668248, -2, -1, 668248, -2, -1, 668248, -2, -1,

aa value of B* is:
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,

说明只要我们加上virtual,在delete的时候编译器是知道怎么delete的。


 


但是这并不是C++标准中制定的,不同的编译器会有不同的结果,比如如果把带virtual的代码放在g++中,会得到如下的结果:

1
2
3
4
5
6
7
8
9
10
11
12
size of A: 8
size of B: 12
A B A B A B A B A B A B A B A B A B A B

aa value of A* is:
1, 134540944, 2, 1, 134540944, 2, 1, 134540944, 2, 1,

aa value of B* is:
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,


Segmentation fault

 


所以,C++中子类的数组不能用父类指针来表示。

Contents