使用父类型时覆盖 C++ 方法

C++ method overriding when using parent type

嘿,当你涉及调用对象作为它们的父类型时,我对方法覆盖的工作方式有点困惑。

这是我的示例代码:

#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;

class A {
public:
    A() {
        std::cout << "Made A.\n";
    }
    void doThing() {
        std::cout << "A did a thing.\n";
    };
};

class B : public A {
public:
    B() {
        std::cout << "Made B.\n";
    }
    void doThing() {
        std::cout << "B did a thing.\n";
    };
};

class C : public A {
public:
    C() {
        std::cout << "Made C.\n";
    }
    void doThing() {
        std::cout << "C did a thing.\n";
    };
};

int main(int argc, char** argv) {
    std::cout << "\n";

    std::cout << "Make objects: \n";
    A a;
    B b;
    C c;

    std::cout << "Call objects normally: \n";
    a.doThing();
    b.doThing();
    c.doThing();

    std::cout << "Call objects as their parent type from a vector: \n";
    vector<A> vect;
    vect.push_back(a); vect.push_back(b); vect.push_back(c);

    for(int i=0;i<vect.size();i++)
        vect.data()[i].doThing();

    return 0;
}

这是我得到的输出:

Make objects: 
Made A.
Made A.
Made B.
Made A.
Made C.
Call objects normally: 
A did a thing.
B did a thing.
C did a thing.
Call objects as their parent type from a vector: 
A did a thing.
A did a thing.
A did a thing.

同样的代码用另一种语言(如 Java)会产生这样的输出:

Make objects: 
Made A.
Made B.
Made C.
Call objects normally: 
A did a thing.
B did a thing.
C did a thing.
Call objects as their parent type from a vector: 
A did a thing.
B did a thing.
C did a thing.

简而言之,我如何在 C++ 中实现第二个输出?

您需要使用 virtual 关键字来使函数在子类中被覆盖。

每当您将 Derived 对象按值传递给采用 Base 的函数时,就会发生称为 "slicing" 的事情。基本上,只使用 Derived 对象的 Base 部分。

您需要通过引用或指针传递对象以避免这些问题。例如,声明

f(Base&)

允许传入一个Derived对象,即允许你写

f(Derived)

此外,要启用 运行 时间多态性,您的函数必须标记为 virtual。 Java 默认情况下所有内容都隐式标记为虚拟。然而,这是 C++,你不需要为你不使用的东西付费(虚函数是一种开销)。

PS:在您的代码中,即使您愿意,也不能使用 std::vector 个引用。但是,您可以使用 std::reference_wrapper 包装对象,这样您就可以 "simulate" 一个 std::vector 的引用:

std::vector<std::reference_wrapper<A>> vect

并使用 get 成员函数检索引用

for(int i=0;i<vect.size();i++)
    vect[i].get().doThing();

或者,也许更简单,只需使用 std::vector<A*>

好的所以这是正在发生的事情: 制作对象: 我认为 A 很明显。 A 对象被构建并且它的默认构造函数打印

Made A

当您首先实例化一个 B 对象时,它的父对象 class 被完全构建。所以在这种情况下,父 class 是 A 它是用默认构造函数构造的,它打印出

Made A 

之后 B class 剩余的部分被构建并且 运行 打印出它的构造函数

Made B

实例化 C 时也会发生同样的事情

在对象上调用函数: 它只是一个简单的函数调用,因为你覆盖了每个 class 中的函数,它们被调用而不是父函数。

当您创建对象的向量时,您将对象复制到其中,因为您既不传递引用也不传递指针。您还没有编写复制构造函数,因此默认的逐位复制将 运行。通过这种方式,您可以从 B class 对象得到一个 A class 对象,该函数将打印出 A did thing 而不是 B did thing。 C 也是如此。