鉴于基本结构和派生结构,我想编写一种方法,该方法可以根据某些输入(例如,基于int,字符串等)返回任何一个。
到目前为止,我已经尝试了各种代码片段,如下所示:
struct Base {
std::string name = "Base";
};
struct Derived1 : Base {
std::string name = "Derived1";
};
struct Derived2 : Base {
std::string name = "Derived2";
};
template<class T>
T string_to_struct(std::string s) {
if(s== "Derived1") {
return Derived1();
} else if(s == "Derived2") {
return Derived2();
} else {
return Base();
}
}
我主要调用函数:
void test2() {
std::string s = "Derived1";
auto bb = string_to_struct<Base>(s);
std::cout << bb.name << std::endl;
}
现在,如果s与“ Derived1”匹配,则我希望打印“ Derived1”,如果等于“ Derived2”,则打印“ Derived2”,依此类推。但是,以上代码无效,并且string_to_struct在任何情况下都将返回“ Base”的实例。我该怎么解决?
答案 0 :(得分:4)
string_to_struct
总是按值返回Base
(因为您要求这样做)。由于bb
的静态类型是Base
,因此bb.name
始终引用Base::name
。而且由于您按值返回,所以bb
的动态类型也将始终为Base
。
您需要做两件事才能得到想要的东西:
不要通过Base
值返回多态对象。如果在函数中创建它们,则最佳返回值为std::unique_ptr<Base>
。原因:您需要引用或指针才能使用多态。
请勿使用依赖于对象的静态类型的访问,例如.name
。您想使用bb
的动态类型,这是最容易使用的虚拟方法,例如:
virtual std::string getName() const
与依靠(非常脆弱的)名称隐藏相比,这也是一种更清洁的解决方案。
答案 1 :(得分:0)
以上情形中的最佳情况是使用static_cast。相应的代码段如下所示:
Base* string_to_struct7(std::string s) {
if(s== "Derived1") {
return new Derived1();
} else if(s == "Derived2") {
return new Derived2();
} else {
return new Base();
}
然后进行进一步处理:
auto t = string_to_struct7(s);
auto bb7 = static_cast<Derived1*>(t);
std::cout << bb7->name<< std::endl;
这正是我想要的。派生类成员现在可以直接寻址。
Max Langhof的答案当然也是有效的。像getter方法那样使用简单的Java可以工作,但是缺点是必须在每个类中为每个类成员定义它们,这可能很快就会失控。
更多信息也可以在这里找到:C++ Access derived class member from base class pointer
编辑:第三种方法是在派生类内部使用包装对象和虚拟getter方法。目前,我很难想到缺点-除了难看。