5

对不起,如果这个答案已经在这个网站上,但我已经看了一遍,找不到任何解决我的问题的方法。它与继承类中的同名函数有关。这是我的代码:

class A
{
public:
    int foo(int c) { c = c+1; return c; };
};

class B : public A
{
public:
    int foo(int c) { c = c-1; return c; };
};

int main()
{
    A array[2];
    array[0] = A item1;
    array[1] = B item2;
    for (int n=0;n<2;n++)
    {
        cout << array[n].foo(10) << endl;
    }
    return 0;
}

我希望输出:

11    // foo() from A class  [10 + 1 = 11]
9     // foo() from B class  [10 - 1 = 9 ]

但相反我得到

11
11

通过测试,我发现 B 类中的 foo() 函数没有在 for 循环中被调用。相反,调用了 A 类中的 foo() 函数,即使是在数组 [1] 处的 B 对象上也是如此。

这是因为我将数组定义为仅包含 A 类的对象吗?如果是这样,有没有办法可以在该 for 循环中的第二个对象上调用 B 类中的 foo() 函数?

预先感谢您的任何帮助!

4

3 回答 3

9

我会忘记这array[0] = A item1;不是有效的 C++,只是假设您正在分配一个类型为的对象和一个类型Aarray[0]B对象array[1]。好的,所以你有两个问题。

第一个称为对象切片。当您将 type 的对象复制到 typeB的对象时A,您只复制了A该对象的一部分。所以你所拥有的array[1]根本不是 a B,它只是一个A. 如果你想要多态(你这样做),那么你需要使用提供多态行为的指针或引用。这意味着让你的数组 an A* array[2];and do array[0] = &item1; array[1] = &item2;

现在,当您在指向 a 的指针上调用函数时AB它仍然只会调用 Asfoo成员函数。为什么?因为默认情况下,函数会在对象的静态类型上查找。该静态类型是A. 如果你想告诉编译器在你的对象的动态类型上查找你的函数——你的对象的真实类型,也就是B——你需要使那个成员函数成为虚拟的。所以在 中A,做:

virtual int foo(int c) { c = c+1; return c; };

现在,当您的编译器看到您正在调用fooanA*时,它会看到它是虚拟的并说“哦,好吧,我应该动态查找这个函数”,它会找到B.foo

于 2012-12-04T21:06:39.123 回答
6

您正在将您的B实例分配给为某种A类型分配的空间。这导致“切片”。

因此,首先,您必须通过指针或引用允许其他类型。例如:

A* a = new B;
a->foo(10);

您必须做的另一件事是提醒编译器foo()可以覆盖。在 C++ 中,将其声明为virtual函数:

virtual int foo(int c) { c = c+1; return c; };
于 2012-12-04T21:05:08.273 回答
4

您缺少virtual关键字。

 class A
 {
   virtual int foo(int c) { c = c+1; return c; };
 };

此外,为了避免切片,而不是A使用指向数组的指针数组A

A* array[2];
array[0] = new A;
array[1] = new B;
for (size_t i=0; i<2; ++i)
    cout << array[i]->foo(10) << endl;

或者,更好的是,使它成为指向 A ( std::vector<A*>) 的指针向量。

此外,根据经验,基类的析构函数也应该是虚拟的 - 对于这个特定示例来说这不是问题,但是如果派生类添加了新成员,它们应该在销毁时释放,使基类析构函数成为虚拟将确保层次结构中的所有析构函数都被调用。

另一件事,这个:

array[1] = B item2;

不会编译。如果将数组声明为指向 A 的指针数组(或指向 A 的指针向量),您将能够:

array[1] = new B;
于 2012-12-04T20:59:45.830 回答