使用父类型时重写C++方法

C++ method overriding when using parent type

本文关键字:重写 C++ 方法 类型 父类      更新时间:2023-10-16

Heyo,当您将对象作为其父类型进行调用时,我对方法重写的工作方式有点困惑。

这是我的示例代码:

#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++中实现第二个输出

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

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

f(Base&)

允许传入Derived对象,即允许您写入

f(Derived)

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

PS:在您的代码中,即使您愿意,也不能使用引用的std::vector。但是,您可以使用std::reference_wrapper包装对象,这允许您"模拟"引用的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*>

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

好的,下面是发生的事情:生成对象:我认为A很明显。构建A对象,其默认构造函数打印

Made A

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

Made A 

之后,B类的剩余部分被构造并运行其构造函数,该构造函数打印出

Made B

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

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

当你创建一个对象的向量时,你会将对象复制到它们中,因为你既不传递引用也不传递指针。您尚未编写复制构造函数,因此将运行默认的逐位复制。通过这种方式,从B类对象中得到一个a类对象,函数将打印出a做了什么,而不是B做了什么。C.也是如此