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 ++中实现第二个输出?
答案 0 :(得分:1)
您需要使用virtual
关键字来启用在子类中覆盖的函数。
答案 1 :(得分:1)
每当您将Derived
对象按值传递给采用Base
的函数时,就会发生称为“切片”的事件。基本上,只使用Base
对象的Derived
部分。
您需要通过引用或指针传递对象以避免这些问题。例如,声明
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*>
答案 2 :(得分:1)
好的,这就是发生的事情: 制作物品: 我认为A非常明显。构造A对象并打印其默认构造函数
Made A
首先实例化B对象时,其父类将完全构造。所以在这种情况下,父类是A,它使用默认构造函数构造,打印出
Made A
之后,B类剩余部分被构造并运行其打印输出的构造函数
Made B
实例化C
时会发生同样的事情调用对象上的函数: 它只是一个简单的函数调用,因为你在每个类中覆盖它们被调用的函数而不是父函数。
当您创建对象的矢量时,您将对象复制到它们中,因为您不传递引用也不传递指针。您还没有编写复制构造函数,因此将运行默认的逐位复制。这样从B类对象中你得到一个A类对象,该函数将打印出A做的事情而不是B做的事情。 C也是如此。