如何处理将派生数组 class 作为参数传递给接受基数组 class 的函数?
How to handle passing an array of derived class as argument in a function that accepts array of base class?
我有下面的示例代码 2 类:
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];
但还不完全清楚为什么它不能很好地与以前的实现配合使用。
您提出的解决方案实际上是正确的,但您可能希望使用 virtual 关键字使 B 抽象。
另一种选择是重新定义 sum 函数并使其接受 D 对象。
解释为什么您的原始实施不起作用的直观方法如下:
在 sum 的主体中,我们有这行代码:
sum += a[i].b;
其中 a 是指向 B 类型对象的指针。
这意味着为了获取索引 i
处的元素,我们需要添加
i * sizeof(B)
到基地址a。但是这个地址现在错了,我们需要地址 i * sizeof(D)
。
通过声明指向 B 的指针类型,此问题得到解决。
顺便说一句,您可能还希望将 b 变量设为受保护,将 d 设为私有,然后提供吸气剂。
D
数组永远不会像 B
数组,因为这些类型的大小不同。 D
的大小比 B
大,因此 D
数组中的连续元素将 spaced 分开(因为每个元素占用更多 space) 比 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[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;
}
我有下面的示例代码 2 类:
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];
但还不完全清楚为什么它不能很好地与以前的实现配合使用。
您提出的解决方案实际上是正确的,但您可能希望使用 virtual 关键字使 B 抽象。 另一种选择是重新定义 sum 函数并使其接受 D 对象。
解释为什么您的原始实施不起作用的直观方法如下:
在 sum 的主体中,我们有这行代码:
sum += a[i].b;
其中 a 是指向 B 类型对象的指针。
这意味着为了获取索引 i
处的元素,我们需要添加
i * sizeof(B)
到基地址a。但是这个地址现在错了,我们需要地址 i * sizeof(D)
。
通过声明指向 B 的指针类型,此问题得到解决。
顺便说一句,您可能还希望将 b 变量设为受保护,将 d 设为私有,然后提供吸气剂。
D
数组永远不会像 B
数组,因为这些类型的大小不同。 D
的大小比 B
大,因此 D
数组中的连续元素将 spaced 分开(因为每个元素占用更多 space) 比 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[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;
}