2017-05-03 96 views
0

我有4個類:Foundation,FoundationWidget,GameGameWidgetFoundationWidget延伸FoundationGameWidget延伸GameC++ std :: array cast

Game還包含Foundation秒的標準::陣列和GameWidget包含FoundationWidget秒的標準::陣列。 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

如果'FoundationWidget'從'Foundation'繼承爲什麼不只是有一個'的std ::陣列<基金會*,4>'(或'其他一些指針類型GameWidget'? – NathanOliver

+0

也,你回來'STD :: array *'這是一個指針類型,如果你正在考慮類似getter的東西,你應該小心不要返回一個臨時/局部變量的指針 –

+0

@NathanOliver謝謝你的評論。已經解決了這個問題,但是我仍然對這個演員感興趣 – sveatlo

回答

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

請注意,使用'array ,4>',數組初始化爲空'unique_ptr's,而OP的值數組具有默認構造的'Foundation'和'FoundationWidget's。 'generate(foundations.begin(),foundations.end(),make_unique );'call將初始化Foundations – Caleth

+0

@Caleth生成不夠好,因爲你不能複製唯一的指針。我想你錯過了一個lambda。我的意思是,我們都不是? – Yakk

+0

一個lambda將definatly工作,但iirc生成不會複製,它分配http://en.cppreference.com/w/cpp/algorithm/generate「該類型的Ret必須是這樣的,一個ForwardIt類型的對象可以被解除引用並分配了類型Ret的值。「你在想'std :: fill'嗎? – Caleth

1

A GameWidget對象包含一個4 FoundationWidget對象的數組,也包含一個不同數組的對象(間接地通過其基類子對象)。如果這是你想要的,那很好。我以某種方式懷疑它,並假設你確實想要別的東西,儘管遏制問題與返回類型get_foundations()的問題無關。

無論哪個對象包含哪個數組,這兩個數組類型都不會形成協變返回類型。只有通過繼承相關的類以及指向這些類的指針/引用可能會形成協變返回類型。std::array這樣的類和指向這樣的數組和數組的指針of指向這樣的類的指針等本身並不相關,不能共同使用。所以你的期望很不幸在現實中沒有支持。

也沒有辦法可靠地投出這樣的對象的數組。

有幾種方法可以實現你想要的,比其他更多的參與。

  1. 使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. 不要暴露數組。

    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. 創建根基的家庭定製的容器,從而FoundationWidgetArray繼承FoundationArray(這可能是太長時間在這裏展示)。