如何处理将派生数组 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;
}