简体   繁体   English

我如何正确地从嵌套结构派生?

[英]How do I properly derive from a nested struct?

I have an abstract (templated) class that I want to have its own return type InferenceData .我有一个抽象(模板化)类,我希望它有自己的返回类型InferenceData

template <typename StateType>
class Model {
public:
    struct InferenceData;
    virtual InferenceData inference () = 0;
};

Now below is an attempt to derive from it现在下面是一个尝试从中派生

template <typename StateType>
class MonteCarlo : public Model<StateType> {
public:
    
    // struct InferenceData {};
    
    typename MonteCarlo::InferenceData inference () {
        typename MonteCarlo::InferenceData x;
        return x;
    }
};

This works, but only because the definition of MonteCarlo::InferenceData is commented out.这有效,但仅仅是因为MonteCarlo::InferenceData的定义被注释掉了。 If it is not commented, I get invalid covariant return type error.如果没有注释,我会收到无效的协变返回类型错误。 I want each ModelDerivation<StateType>::InferenceData to be its own type and have its own implementation as a struct.我希望每个ModelDerivation<StateType>::InferenceData都是自己的类型,并有自己的结构作为实现。 How do I achieve this?我如何实现这一目标?

You cannot change the return type of a derived virtual method.您不能更改派生虚拟方法的返回类型。 This is why your compilation failed when you try to return your derived InferenceData from MonteCarlo::inference() .这就是当您尝试从MonteCarlo::inference()返回派生的InferenceData时编译失败的原因。

In order to achieve what you need, you need to use a polymorphic return type, which requires pointer/reference semantics .为了实现您所需要的,您需要使用多态返回类型,这需要指针/引用语义 For this your derived InferenceData will have to inherit the base InferenceData , and inference() should return a pointer/reference to the base InferenceData .为此,您派生的InferenceData必须继承基础InferenceData ,并且inference()应该返回对基础InferenceData的指针/引用。

One way to do it is with a smart pointer - eg a std::unique_ptr - see the code below:一种方法是使用智能指针 - 例如std::unique_ptr - 请参见下面的代码:

#include <memory>

template <typename StateType>
class Model {
public:
    struct InferenceData {};
    virtual std::unique_ptr<InferenceData> inference() = 0;
};


template <typename StateType>
class MonteCarlo : public Model<StateType> {
public:
    struct InferenceDataSpecific : public Model<StateType>::InferenceData {};

    virtual std::unique_ptr<Model::InferenceData> inference() {
        return std::make_unique<InferenceDataSpecific>();
    }
};

int main()
{
    MonteCarlo<int> m;
    auto d = m.inference();
    return 0;
}

Note: if you need to share the data, you can use a std::shared_ptr .注意:如果您需要共享数据,可以使用std::shared_ptr

You have to make the return type part of the template arguments:您必须将返回类型作为模板参数的一部分:

template <typename StateType, typename InferenceData>
class Model {
public:
    virtual InferenceData inference () = 0;
};

Then you can set the return type when you derive from it.然后,您可以在派生时设置返回类型。

You can actually have your MonteCarlo::inference return a pointer (or reference) to a MonteCarlo::InferenceData , as long as you do things correctly otherwise.您实际上可以让您的MonteCarlo::inference返回指向MonteCarlo::InferenceData的指针(或引用),只要您以其他方式正确执行操作即可。 A simple version looks like this:一个简单的版本如下所示:

#include <memory>
#include <iostream>

template <typename StateType>
class Model {
public:
    // base return type:
    struct InferenceData { };

    virtual InferenceData *inference() = 0;
};

template <typename StateType>
class MonteCarlo : public Model<StateType> {
public:
    // derived return type must be derived from base return type:
    struct InferenceData : public ::Model<StateType>::InferenceData { };

    InferenceData *inference() { return new InferenceData; }
};

int main() {
    MonteCarlo<int> mci;
    auto v = mci.inference();
}

This aa covariant return type (as the compiler alluded to in its error message).这是一个协变返回类型(正如编译器在其错误消息中所暗示的那样)。 There are a couple of points to keep in mind here though:不过,这里有几点需要牢记:

  1. The return type really does have to be covariant.返回类型确实必须是协变的。 That is, the base class function has to be declared to return a pointer/reference to some base class, and the derived function has to return a pointer/reference to a type derived from that that the base function returns.也就是说,必须声明基类函数以返回指向某个基类的指针/引用,而派生函数必须返回指向从基函数返回的类型派生的类型的指针/引用。
  2. A unique_ptr<Derived> allows implicit conversion to unique_ptr<Base> , assuming Derived is derived from Base , but a unique_ptr<Derived> still isn't actually derived from unique_ptr<Base> , so you can't use (most typical) smart pointers for covariant returns.一个unique_ptr<Derived>允许隐式转换为unique_ptr<Base> ,假设Derived是从Base派生的,但unique_ptr<Derived>实际上仍然不是从unique_ptr<Base>派生的,所以你不能使用(最典型的)智能协变返回的指针。

For the moment, I've used new to create the returned object.目前,我使用new来创建返回的对象。 That's pretty common when dealing with derivation and such, but it can be avoided if necessary.这在处理推导等时很常见,但如有必要可以避免。 Doing that can get non-trivial in itself, depending on your needs.根据您的需要,这样做本身就很重要。 In a really simple case, define a static object of the correct type, and return a pointer to it (but that leads to problems if you do multi-threading).在一个非常简单的情况下,定义一个正确类型的静态对象,并返回一个指向它的指针(但是如果你使用多线程,这会导致问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM