简体   繁体   English

C ++ std :: array转换

[英]C++ std::array cast

I have 4 classes: Foundation , FoundationWidget , Game and GameWidget . 我有4个类别: FoundationFoundationWidgetGameGameWidget FoundationWidget extends Foundation and GameWidget extends Game . FoundationWidget扩展了FoundationGameWidget扩展了Game

Game also contains an std::array of Foundation s and GameWidget contains an std::array of FoundationWidget s. Game还包含一个的std ::阵列Foundation S和GameWidget包含一个std ::阵列FoundationWidget秒。 Game also contains a virtual method, which should return the pointer to the array of Foundation s. Game还包含一个虚拟方法,该方法应将指针返回到Foundation数组。 GameWidget overrides this method by returning a pointer to the array of its FoundationWidget s. GameWidget通过返回指向其FoundationWidget数组的指针来覆盖此方法。 The current (non-working) implementation looks like this: 当前(无效)的实现如下所示:

class Game {
    std::array<Foundation, 4> foundations;
private:
    virtual std::array<Foundation, 4>* get_foundations() {
        return &this->foundations;
    }
}

class GameWidget : public Game {
    std::array<FoundationWidget, 4> foundations;
private:
    std::array<Foundation, 4>* get_foundations() {
        return &this->foundations;
    }
}

I'd expect this to work, since it's an array of the same size with class, that extends the one specified as return type, but instead I'm getting this error: cannot convert 'std::array<FoundationWidget, 4ul>*' to 'std::array<Foundation, 4ul>*' in return . 我希望它能正常工作,因为它是与类大小相同的数组,可以扩展指定为返回类型的数组,但我却收到此错误: cannot convert 'std::array<FoundationWidget, 4ul>*' to 'std::array<Foundation, 4ul>*' in return

I've also tried to declare the class attributes as arrays of pointers, but the result was the same. 我也尝试过将类属性声明为指针数组,但是结果是相同的。 Neither static_cast or dynamic_cast helped. static_cast或dynamic_cast都没有帮助。

What am I missing here? 我在这里想念什么? Is there any way to cast arrays? 有什么方法可以转换数组吗? If not, can I use some construction to get the same results, ie "virtual" class members? 如果没有,我可以使用某种构造来获得相同的结果,即“虚拟”班级成员吗?

Arrays are packed values of a certain type of data. 数组是某种数据类型的打包值。

Arrays of different types are not compatible as arrays. 不同类型的数组不兼容。 Their size can differ, for example. 例如,它们的大小可以不同。 And arrays are packed, so an array of elements of size 7 and an array of elements of size 8 are not going to work. 而且数组是打包的,因此大小为7的元素数组和大小为8的元素数组将无法工作。

Even if they are the same size, C++ dictates the arrays are not convertible. 即使它们大小相同,C ++也会指出数组不可转换。

You can fix this by having array<unique_ptr<Base>, N> -- arrays of (smart) pointers. 您可以通过使用array<unique_ptr<Base>, N>来解决此问题-(智能)指针的数组。 One could also write a type erasure any_derived<Base, size_limit> type and have an array<any_derived<Base, size_limit>, N> and store them contiguously, if you want to avoid the extra fragmentation and allocations. 如果您想避免额外的碎片和分配any_derived<Base, size_limit>也可以编写一个类型为any_derived<Base, size_limit>类型并具有array<any_derived<Base, size_limit>, N>并连续存储它们,如果要避免额外的碎片和分配。

But really just use unique_ptr . 但实际上只使用unique_ptr

using foundations_t = std::array<std::unique_ptr<Foundation>, 4>;
template<class T> struct tag_t {};
struct HasFoundation {
  foundations_t foundations;
  HasFoundation( tag_t<T> ) {
    std::generate(foundations.begin(), foundations.end(), []{return std::make_unique<T>(); } );
  }
  HasFoundation(HasFoundation const&)=delete;
  HasFoundation(HasFoundation&&)=default;
  HasFoundation& operator=(HasFoundation const&)=delete;
  HasFoundation& operator=(HasFoundation&&)=default;
};
class Game:HasFoundation {
protected:
  template<class T>
  Game(tag_t<T> tag):HasFoundation(tag){}
public:
  Game():Game(tag_t<Foundation>{}) {}
  virtual foundations_t* get_foundations() {
    return &this->foundations;
  }
};

class GameWidget : public Game {
public:
  GameWidget():Game(tag_t<FoundationWidget>{}) {}
};

here we have one storage class, and what it stores is determined at construction time. 这里我们有一个存储类,它存储的是在构建时确定的。

A template version would require all logic in Game be exposed in header files. 模板版本要求将Game所有逻辑公开在头文件中。 This one instead requires that all access to the "real" type of the foundations elements requires runtime dispatch. 相反,这需要对foundations元素的“实际”类型的所有访问都需要运行时调度。

A GameWidget object contains an array of 4 FoundationWidget objects and also a different array of 4 Foundation objects (indirectly via its base class subobject). GameWidget对象包含4个的阵列FoundationWidget对象,并且也是不同阵列4点的Foundation的对象(通过它的基类的子对象间接地)。 If this is what you want, fine. 如果这是您想要的,那就好。 I somehow doubt it and going to assume you do want something else, though the issue of containment is unrelated to the issue of the return type of get_foundations() . 我以某种方式对此表示怀疑,并假设您确实想要其他东西,尽管遏制问题与get_foundations()返回类型的问题无关。

Regardless of what object contains which array, these two array types do not form covariant return types. 无论哪个对象包含哪个数组,这两种数组类型都不构成协变返回类型。 Only classes related by inheritance and pointers/references to such classes may form covariant return types. 只有与继承相关的类以及对此类的指针/引用才能形成协变返回类型。 std::array s of such classes and pointers to such arrays and arrays of pointers to such classes etc are not related by inheritance themselves and cannot be used covariantly. 这样的类的std::array ,指向此类的数组指针以及指向此类指针的数组等与继承本身无关,因此不能协变地使用。 So your expectations unfortunately have no support in reality. 因此,不幸的是您的期望没有现实支持。

There is also no way to reliably cast arrays of such objects. 也没有办法可靠地转换此类对象的数组。

There are several ways to achieve what you want, some more involved than others. 有几种方法可以实现您想要的目标,其中一些方法比其他方法更复杂。

  1. Make Game a template. 使Game成为模板。

     template <class F> class Game { std::array<F, 4> foundations; private: virtual std::array<F, 4>* get_foundations() { return &this->foundations; } }; class GameWidget : public Game<FoundationWidget> { // nothing here! }; 
  2. Do not expose arrays. 不要公开数组。

     class Game { virtual Foundation* get_foundation (int) = 0; }; class GameWidget : public Game { FoundationWidget* get_foundation (int i) { return &foundations[i]; } std::array<FoundationWidget, 4> foundations; }; 
  3. Create a family of custom containers for foundations such that FoundationWidgetArray inherits FoundationArray (this is probably too long to show here). 为基础创建一系列自定义容器,以使FoundationWidgetArray继承FoundationArray (此处可能太长了,无法在此处显示)。

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

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