2017-02-12 21 views
2

OOPを使用しているので、プラットフォームに依存しないコードを作成しようとしています。たとえば、Windows、Mac OS X、Linuxではウィンドウができますが、アンドロイドにはビューがありますので、これを抽象化しようとしています。この場合、dynamic_castよりも優れたソリューションがありますか?

私は最初のウィンドウまたは私はビューと呼ばれるビューを表現するクラスを作っ:

class View 
{ 
public: 
    virtual ~View() 
    {} 

    virtual void display() = 0; 
    virtual void hide() = 0; 
}; 

さて問題は、Windows上で私が決めたがある一方でAndroid上で、ビューにはタイトルがないことです別のクラスを作成する:最後に、その後

class NameableView : public View 
{ 
public: 
    virtual void setName(const std::string& name) 
}; 

をとクラスを実装:

class WindowsView : public NameableView 
{ 
    /* Windows implementation */ 
} 

class AndroidView : public View 
{ 
    /* Android implementation */ 
} 

次に、可能な場合にのみビューの名前を設定するコードを作成する必要があります(NameableViewクラスから継承する場合)。

どうすればこの問題を解決できますか?私は最初にdynamic_castについて考えましたが、あまりにも多くのことを聞いたことがよくあります。dynamic_castはデザイン上の問題の兆候です。私はC++の初心者ですので、正しい方法がないと思われ、デザイン全体を変更する必要があります。

+0

'setName'を' View'に実装されたno-op関数にしますか?抽象化ブレーカはそんなにありません。 – StoryTeller

+1

*「私はプラットフォームに依存しないコードを作っていますので、OOPを使用しています。」* - それはまずは​​悪い考えです。 **仮想機能**のOOPのポイントは、アプリケーションの実行中に何かの実装を選択して変更できることです。 –

+1

まったく異なるGUI環境のための抽象的な「基本コンセプト」を設計しようとするのは間違いです。より良い設計は、それぞれ独自のシステムのニーズに応じて、互いに独立してGUIを開発し、共通のビジネスロジックコンポーネントまたはバックエンドを使用可能にすることです。 –

答えて

3

私はOOPを使用しているので、プラットフォームに依存しないコードを作成しようとしています。

これは最適な方法ではありません - 多型階層とvirtual機能は、実行時で異なっを振る舞うように同じインタフェースを継承異なる具体的なオブジェクトタイプを許可していますが、ターゲットにするつもりだプラットフォームを知っていますコンパイル時に

代わりに、静的多型とCRTPを使用して、プラットフォームごとの具体的な実装が満たさなければならない共通のインターフェイスを提供する必要があります。 setNameの場合

template <typename TDerived> 
struct View 
{ 
    void display() { static_cast<TDerived&>(*this).display(); } 
    void hide() { static_cast<TDerived&>(*this).hide(); } 

    constexpr bool supportsSetView() const 
    { 
     return static_cast<TDerived&>(*this).supportsSetView(); 
    } 
}; 

、あなたはビューが名前を付けることができた場合、コンパイル時にtrueを返し、すべてのプラットフォーム上でsupportsSetViewチェックを提供する必要があります。次に、呼び出し側でそのチェックを実行し、チェックが合格した場合にのみsetNameを呼び出します。

使用例:

#if defined(PLATFORM_ANDROID) 
struct AndroidView 
{ 
    // ... 
    constexpr bool supportsSetView() const { return false; } 
}; 

using MyView = View<AndroidView>; 
#else if defined(PLATFORM_WINDOWS) 
struct WindowsView 
{ 
    // ... 
    constexpr bool supportsSetView() const { return true; } 
    void setName(std::string x) { /* ... */ } 
}; 

using MyView = View<WindowsView>; 
#else 
#error "Unsupported platform." 
#endif 

発信側:

MyView currentView; 

if constexpr(currentView.supportsSetView()) 
{ 
    currentView.setName("something"); 
} 

if constexpr(...)の評価は、コンパイル時に発生するように、それがMyViewによってサポートされている場合、コードはsetNameを呼び出します。

関連する問題