常见错误89:持有class对象的数组
当心持有class对象的数组,尤其是持有基类对象的数组。
数组的索引操作只是指针算术的缩写,因此array[i]等价于*(array+i)。不幸的是,编译器
会基于“array指针指向有B对象的数组”的前提做指针的加法运算。如果派生对象具有更大的
尺寸,或迥异的内存布局,那么索引操作将取得错误的地址。
用于访问持有基类对象的数组指针运算通常不能用于访问持有派生类对象的数组。
持有基类对象的数组一般而言是不提倡使用的,而持有class对象的数组都得受到严密监视。
较佳的做法是让数组持有指向class对象的指针,而非class对象本身,这么一来,就可以在数组上进行多态
应用,而不会引发指针算术相关的错误。
当心持有class对象的数组,尤其是持有基类对象的数组。
数组的索引操作只是指针算术的缩写,因此array[i]等价于*(array+i)。不幸的是,编译器
会基于“array指针指向有B对象的数组”的前提做指针的加法运算。如果派生对象具有更大的
尺寸,或迥异的内存布局,那么索引操作将取得错误的地址。
用于访问持有基类对象的数组指针运算通常不能用于访问持有派生类对象的数组。
持有基类对象的数组一般而言是不提倡使用的,而持有class对象的数组都得受到严密监视。
较佳的做法是让数组持有指向class对象的指针,而非class对象本身,这么一来,就可以在数组上进行多态
应用,而不会引发指针算术相关的错误。
更佳的做法是彻底舍弃裸数组,而使用某种标准库中的容器组件,一般选用vector组件。
apply.cpp
#include <iostream>
struct B {
B() { a = 1; b = 2; }
int a, b;
};
void apply( B array[], int length, void (*f)( B & ) ) {
for( int i = 0; i < length; ++i )
f( array[i] );
}
void somefunc( B &b ) {
std::cout << "B::a = " << b.a << " , B::b = " << b.b << std::endl;
}
struct D : public B {
D() { c = 3; d = 4; }
int c, d;
};
int main() {
D *dp = new D[3];
apply( dp, 3, somefunc ); // 灾难爆发
getchar();
return 0;
}
输出
B::a = 1 , B::b = 2
B::a = 3 , B::b = 4
B::a = 1 , B::b = 2