函数 return 不同类型
Function return different types
给定一个基本结构和派生结构,我想编写一个方法,可以 return 它们中的任何一个取决于一些输入,例如 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();
}
}
在 main 中我调用函数:
void test2() {
std::string s = "Derived1";
auto bb = string_to_struct<Base>(s);
std::cout << bb.name << std::endl;
}
现在我希望打印 "Derived1" 如果 s 匹配 "Derived1","Derived2" 如果它等于 "Derived2" 等等。但是,上面的代码不起作用,并且 string_to_struct return 在任何情况下都是 "Base" 的实例。我该如何解决?
string_to_struct
总是 returns a Base
按值(因为你要求那个)。由于 bb
的静态类型是 Base
,因此 bb.name
总是引用 Base::name
。并且由于您按值 return,因此 bb
的动态类型也将始终为 Base
.
您需要做两件事才能得到您想要的:
不要通过 Base
值 return 多态对象。如果它们是在函数中创建的,最好的 return 值将是 std::unique_ptr<Base>
。原因:您需要引用或指针才能使多态工作。
不要使用依赖对象静态类型的访问,例如.name
。您想使用 bb
的 动态类型 ,这最容易用虚方法实现,例如:
virtual std::string getName() const
与依赖(非常脆弱的)名称隐藏相比,这也是一种更清洁的解决方案。
上述情况下的最佳情况是使用 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;
这正是我想要的。派生 class 成员现在可以直接寻址。
Max Langhof 的回答当然也是有效的。像 getter 方法一样简单地使用 Java 方法是可行的,但缺点是它们必须在每个 class 中为每个 class 成员定义,这很快就会失控。
更多信息也可以在这里找到:C++ Access derived class member from base class pointer
编辑:第三种方法是在 Derived 类 和虚拟 getter 方法中使用包装器对象。目前我想不出缺点 - 除了丑陋。
给定一个基本结构和派生结构,我想编写一个方法,可以 return 它们中的任何一个取决于一些输入,例如 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();
}
}
在 main 中我调用函数:
void test2() {
std::string s = "Derived1";
auto bb = string_to_struct<Base>(s);
std::cout << bb.name << std::endl;
}
现在我希望打印 "Derived1" 如果 s 匹配 "Derived1","Derived2" 如果它等于 "Derived2" 等等。但是,上面的代码不起作用,并且 string_to_struct return 在任何情况下都是 "Base" 的实例。我该如何解决?
string_to_struct
总是 returns a Base
按值(因为你要求那个)。由于 bb
的静态类型是 Base
,因此 bb.name
总是引用 Base::name
。并且由于您按值 return,因此 bb
的动态类型也将始终为 Base
.
您需要做两件事才能得到您想要的:
不要通过
Base
值 return 多态对象。如果它们是在函数中创建的,最好的 return 值将是std::unique_ptr<Base>
。原因:您需要引用或指针才能使多态工作。不要使用依赖对象静态类型的访问,例如
.name
。您想使用bb
的 动态类型 ,这最容易用虚方法实现,例如:virtual std::string getName() const
与依赖(非常脆弱的)名称隐藏相比,这也是一种更清洁的解决方案。
上述情况下的最佳情况是使用 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;
这正是我想要的。派生 class 成员现在可以直接寻址。
Max Langhof 的回答当然也是有效的。像 getter 方法一样简单地使用 Java 方法是可行的,但缺点是它们必须在每个 class 中为每个 class 成员定义,这很快就会失控。
更多信息也可以在这里找到:C++ Access derived class member from base class pointer
编辑:第三种方法是在 Derived 类 和虚拟 getter 方法中使用包装器对象。目前我想不出缺点 - 除了丑陋。