我有基类Parent类和模板化的Child类。 我想在集合中使用Childs来通过Parent的多态接口枚举它们。 我希望虚拟(多态)函数调用 - 但我只有对Parent :: print()的静态类型调用
#include <iostream>
#include <vector>
using namespace std;
class Parent {
public:
Parent() { cout << " parent ctor "; }
virtual void print() { cout << " Parent::print "; }
};
template <typename T>
class Child : public Parent {
public:
Child(T value) : var(value) { cout << " child ctor "; }
virtual void print() { cout << " Child::print " << var; }
protected:
T var;
};
int main() {
Child<int> myChild(1);
Child<double> myDoubleChild(2.);
vector<Parent> v = {myChild, myDoubleChild};
for (auto i : v) {
i.print();
}
return 0;
}
实际输出:
parent ctor child ctor parent ctor child ctor Parent::print Parent::print
预期输出应包含&#34; Child :: print&#34;虚函数调用
答案 0 :(得分:2)
正如@tchelidze和@StenSoft所提到的,有两个缺陷:
启用动态调度代码应该是这样的:
#include <iostream>
#include <vector>
using namespace std;
class Parent {
public:
Parent() { cout << " parent ctor "; }
virtual void print() { cout << " Parent::print "; }
};
template <typename T>
class Child : public Parent {
public:
Child(T value) : var(value) { cout << " child ctor "; }
virtual void print() { cout << " Child::print " << var; }
protected:
T var;
};
int main() {
Child<int> myChild(1);
Child<double> myDoubleChild(2.);
// vector<Parent> v = {myChild, myDoubleChild};
vector<Parent*> v = {&myChild, &myDoubleChild};
for (auto i : v) {
// i.print();
i->print();
}
return 0;
}
这提供了所需的输出:
parent ctor child ctor parent ctor child ctor Child::print 1 Child::print 2
答案 1 :(得分:1)
原因是Object Slicing。
那就是:
将子类的对象分配给超类时。超类对子类中的附加信息一无所知,也没有足够的空间存储它,因此附加信息被“切掉”
答案 2 :(得分:1)
C ++中的多态性仅适用于引用和指针。 Child
是值的向量。它们构造为Parent
个实例的副本,并且都是vector<Parent> v = { Parent(myChild), Parent(myDoubleChild) };
类型的副本。基本上它的作用是:
Parent
如果您要将print
作为抽象类(例如,将vector<unique_ptr<Parent>>
更改为纯虚方法),您会看到错误。
你需要一个指针向量,例如:
{{1}}
答案 3 :(得分:0)
如上所述,对象切片是问题所在。使用原始指针向量的替代方法是使用std::reference_wrapper向量。
std :: reference_wrapper是一个类模板,它将引用包装在可复制的可分配对象中。它通常用作将引用存储在通常无法保存引用的标准容器(如std :: vector)内的机制
#include <iostream>
#include <functional>
#include <vector>
using namespace std;
class Parent {
public:
Parent() { cout << " parent ctor "; }
virtual void print() { cout << " Parent::print "; }
};
template <typename T>
class Child : public Parent {
public:
Child(T value) : var(value) { cout << " child ctor "; }
virtual void print() { cout << " Child::print " << var; }
protected:
T var;
};
int main() {
Child<int> myChild(1);
Child<double> myDoubleChild(2.);
typedef std::reference_wrapper<Parent> refType;
vector<refType> v = {refType(myChild), refType(myDoubleChild)};
for (auto i : v) {
i.get().print();
}
return 0;
}
此代码的输出是:
parent ctor child ctor parent ctor child ctor Child::print 1 Child::print 2
不是很干净(仍然需要特殊的语法),但可能被认为是更惯用的C ++。