我在下面有两个类的示例代码:
class B {
public:
int b;
};
class D : public B {
public:
int d;
};
我有一个函数接受B作为数组并总结b成员:
int sum(B a[], int count){
int sum = 0;
for(int i = 0; i < count; i++) {
sum += a[i].b;
}
return sum;
}
这是我的主要内容:
int main() {
D* a = new D[3];
for(int i = 0; i < 3; i++)
a[i].b = i+1;
cout << "Sum is " << sum(a, 3) << endl;
return 0;
}
我所知道的是这段代码由于切片而无效。我没有得到正确的输出,应该是6.我试图将sum函数中的参数作为:
int sum(B& a[], int count)
传递一个引用,但这会产生编译错误,因为你不能使用引用数组。
我的问题是,最好的方法是什么?
目前我的解决方案是将我的数组声明为:
B* a = new D[3];
但它并不完全清楚为什么它不适合以前的实施。
答案 0 :(得分:0)
D
数组永远不会像B
数组,因为这些类型的大小不同。 D
的大小大于B
,因此D
数组中的连续元素将比{B
中的连续元素间隔更远(因为每个元素占用更多空间) 1}}数组。
如果要使用子类型多态,则需要使用指针(或引用),而不是对象类型本身。你不能有一个引用数组,所以你必须使用一个指针数组。
这样的事情会起作用:
int sum(B *a[], int count) {
int sum = 0;
for(int i = 0; i < count; i++) {
sum += a[i]->b;
}
return sum;
}
int main() {
D *a[3];
for (int i = 0; i < 3; i++) {
a[i] = new D;
a[i]->b = i+1;
}
cout << "Sum is " << sum((B **)a, 3) << endl;
for (int i = 0; i < 3; i++) {
delete a[i];
}
return 0;
}
请注意,我仍然需要从D **
投射到B **
,因为转换仍然可能导致潜在的不安全因素。如果您已将数组声明为B *[3]
,则不需要强制转换:
int sum(B *a[], int count) {
int sum = 0;
for(int i = 0; i < count; i++) {
sum += a[i]->b;
}
return sum;
}
int main() {
B *a[3];
for (int i = 0; i < 3; i++) {
a[i] = new D;
a[i]->b = i+1;
}
cout << "Sum is " << sum(a, 3) << endl;
for (int i = 0; i < 3; i++) {
delete a[i];
}
return 0;
}
或者您可以使用模板:
template <class T>
int sum(T *a[], int count) {
int sum = 0;
for(int i = 0; i < count; i++) {
sum += a[i]->b;
}
return sum;
}
int main() {
D *a[3];
for (int i = 0; i < 3; i++) {
a[i] = new D;
a[i]->b = i+1;
}
cout << "Sum is " << sum(a, 3) << endl;
for (int i = 0; i < 3; i++) {
delete a[i];
}
return 0;
}
模板也适用于您原来的非指针式方法:
template <class T>
int sum(T a[], int count) {
int sum = 0;
for(int i = 0; i < count; i++) {
sum += a[i].b;
}
return sum;
}
int main() {
D a[3];
for (int i = 0; i < 3; i++) {
a[i].b = i+1;
}
cout << "Sum is " << sum(a, 3) << endl;
return 0;
}
答案 1 :(得分:-1)
您提出的解决方案实际上是正确的,但您可能希望使用virtual关键字进行B抽象。 另一种方法是重新定义sum函数并使其接受D对象。
解释原始实现无法解决的原因的直观方法如下:
在总和中我们有这行代码:
sum += a[i].b;
其中a是指向B类对象的指针。
这意味着为了获得索引i
的元素,我们需要添加
i * sizeof(B)
到基地址a。但是这个地址现在错了,而我们需要地址i * sizeof(D)
。
通过将指针类型声明为B,此问题已修复。
顺便说一下,你可能也想让你的b变量受到保护而d变为私有,然后提供getter。