函数返回不同类型

时间:2018-12-17 13:05:05

标签: c++ templates virtual-functions covariant-return-types

鉴于基本结构和派生结构,我想编写一种方法,该方法可以根据某些输入(例如,基于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”的实例。我该怎么解决?

2 个答案:

答案 0 :(得分:4)

string_to_struct总是按值返回Base(因为您要求这样做)。由于bb的静态类型是Base,因此bb.name始终引用Base::name。而且由于您按值返回,所以bb的动态类型也将始终为Base

您需要做两件事才能得到想要的东西:

  1. 不要通过Base值返回多态对象。如果在函数中创建它们,则最佳返回值为std::unique_ptr<Base>。原因:您需要引用或指针才能使用多态。

  2. 请勿使用依赖于对象的静态类型的访问,例如.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方法。目前,我很难想到缺点-除了难看。