我有4个课程:Foundation
,FoundationWidget
,Game
和GameWidget
。 FoundationWidget
扩展Foundation
,GameWidget
扩展Game
。
Game
还包含Foundation
的std ::数组,GameWidget
包含FoundationWidget
的std ::数组。 Game
还包含一个虚方法,它应该返回指向Foundation
s数组的指针。 GameWidget
通过返回指向其FoundationWidget
数组的指针来覆盖此方法。
当前(非工作)实现如下所示:
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;
}
}
我希望这可以工作,因为它是一个与类相同大小的数组,它扩展了指定为返回类型的数组,但我得到了这个错误:cannot convert ‘std::array<FoundationWidget, 4ul>*’ to ‘std::array<Foundation, 4ul>*’ in return
。
我也尝试将类属性声明为指针数组,但结果是一样的。 static_cast或dynamic_cast都没有帮助。
我在这里缺少什么?有没有办法投射数组?如果没有,我可以使用一些结构来获得相同的结果,即“虚拟”类成员吗?
答案 0 :(得分:2)
数组是某种类型数据的打包值。
不同类型的数组与数组不兼容。例如,它们的大小可以不同。并且数组是打包的,因此大小为7的元素数组和大小为8的元素数组不起作用。
即使它们的大小相同,C ++也要求数组不可转换。
你可以通过array<unique_ptr<Base>, N>
- (智能)指针数组来解决这个问题。如果你想避免额外的碎片和分配,也可以写一个类型擦除any_derived<Base, size_limit>
类型并有一个array<any_derived<Base, size_limit>, N>
并连续存储它们。
但实际上只是使用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>{}) {}
};
这里我们有一个存储类,它存储的内容是在构建时确定的。
模板版本要求Game
中的所有逻辑都在头文件中公开。相反,这要求所有对foundations
元素的“真实”类型的访问都需要运行时调度。
答案 1 :(得分:1)
GameWidget
对象包含4个FoundationWidget
对象的数组,以及4个Foundation
对象的不同数组(间接通过其基类子对象)。如果这是你想要的,那很好。我以某种方式怀疑它,并假设你确实想要别的东西,尽管遏制问题与get_foundations()
的返回类型问题无关。
无论哪个对象包含哪个数组,这两个数组类型都不会形成协变返回类型。只有通过继承相关的类和对这些类的指针/引用才能形成协变返回类型。这些类的std::array
和指向此类数组的 指针到这些类等的指针与继承本身无关,并且不能共同使用。所以不幸的是,你的期望在现实中没有任何支持。
也无法可靠地投射此类物体的数组。
有几种方法可以达到你想要的效果,有些方法比其他方式更多。
将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!
};
不要暴露数组。
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;
};
为基金会创建一系列自定义容器,FoundationWidgetArray
继承FoundationArray
(这可能太长,无法在此处显示)。