2016-04-18 6 views
3

与えられたインタフェースに複数の実装があるが、コンパイル時に必要な特定の実装がわかっている場合は、makeファイルを同じヘッダの異なる実装ファイルに送るだけで間違っていますか?ポリモーフィズムを達成するために、異なる実装ファイルを使用することはできますか?

例えば、自動車(Car.h)を定義するプログラムを持っている場合

// Car.h 
class Car { 
    public: 
    string WhatCarAmI(); 
} 

とビルド時に我々は、それは、フェラーリやフィアットすることのいずれかのそれぞれを与えたいと思うかどうかを知ります対応するファイル:今

// Fiat.cpp 
#include "Car.h" 
string Car::WhatCarAmI() { return "Fiat"; } 

(予想通り)他のケースについてながら

// Ferrari.cpp 
#include "Car.h" 
string Car::WhatCarAmI() { return "Ferrari"; } 

、私は承知しています私はフィアットとフェラーリの両方をCarのオブジェクトから派生させることができ、実行時には私が構築したいものを選ぶことができました。同様に、私はそれをテンプレート化し、コンパイル時にコンパイラを選択させることができます。しかし、この場合、2つの実装はどちらも交差してはならない別々のプロジェクトを参照します。

与えられたプロジェクトのメイクファイルで、正しい.cppを選択するだけで間違っていますか?これを行う最善の方法は何ですか?かなりハックようだ - これは静的な多型であるため

+0

あなたはそうすることができます。それは[Pimpl Idiom]の貧弱なバージョンです(https://en.wikibooks.org/wiki/C%2B%2B_Programming/Idioms#Pointer_To_Implementation_.28pImpl.29)。 –

+3

これは静的なポリモーフィズムなので、CRTP( 'class Fiat:public Car ')を使うと、おそらくcppファイルを取り替えるよりもはるかに慣れていて、複数のインターフェースを共存させたい場合には絶対必要です。 –

+2

できますが、できません。これは、多形性を達成するには非常に貧弱な方法であり、デザインの選択肢は非常に貧弱です。 – Nico

答えて

1

実装

は、不思議な経常テンプレートパターンは、おそらく非常に多くの慣用のcppファイルを交換するよりもです。 1つのプロジェクト内で複数の実装を共存させたいのであればCRTPが必要になりますが、強制実装された単一実装のビルドシステムでは使いやすいです。私はその文書化された性質と両方を行う能力を発揮していると思います。簡単に言うと

、CRTPは少し次のようになります。

template<typename T_Derived> 
class Car { 
public: 
    std::string getName() const 
    { 
     // compile-time cast to derived - trivially inlined 
     return static_cast<T_Derived const *>(this)->getName(); 
    } 

    // and same for other functions... 
    int getResult() 
    { 
     return static_cast<T_Derived *>(this)->getResult(); 
    } 

    void playSoundEffect() 
    { 
     static_cast<T_Derived *>(this)->playSoundEffect(); 
    } 
}; 

class Fiat: public Car<Fiat> { 
public: 
    // Shadow the base's function, which calls this: 
    std::string getName() const 
    { 
     return "Fiat"; 
    } 

    int getResult() 
    { 
     // Do cool stuff in your car 
     return 42; 
    } 

    void playSoundEffect() 
    { 
     std::cout << "varooooooom" << std::endl; 
    } 
}; 

(私は以前d_と派生実装関数を前に付けてきましたが、私は、これは何を得るかわからない、実際には、それはおそらく、あいまいさを増します...)

実際にCRTPで何が起こっているのか理解するには、一度入手すれば簡単です! - 周りにはたくさんのガイドがあります。あなたはおそらくこれに多くのバリエーションを見つけ、あなたが一番好きなものを選ぶでしょう。

戻って他の側面に到達するために実装

のコンパイル時の選択は、あなたがコンパイル時に実装の1つに制限したいならば、あなたが強制するために、いくつかのプリプロセッサマクロ(複数可)を使用することができます派生型、例えば:

g++ -DMY_CAR_TYPE=Fiat 

以降

// #include "see_below.hpp" 
#include <iostream> 

int main(int, char**) 
{ 
    Car<MY_CAR_TYPE> myCar; 

    // Do stuff with your car 
    std::cout << myCar.getName(); 
    myCar.playSoundEffect(); 
    return myCar.getResult(); 
} 

あなたは、単一のヘッダ内のすべての車のバリエーションを宣言し、可能性がどちらかこれらのスレッドで説明したメソッドのようなものを使用してください。Generate include file name in a macro/DynamiC#include based on macro definition - 同じ-Dマクロから#includeを生成してください。

+0

これは記載された問題に対処しません。 –

+0

@ LightnessRacesinOrbitどのように説明してもらえませんか? 「与えられたプロジェクトのメークファイルに正しい.cppを選択するだけで、私が提案したことをするのは間違っていますか?これを行うにはどうすればよいでしょうか?」あなたはcppファイルを交換することがCRTPより優れていると思いますか? –

+0

コードには、使用できるタイプが用意されています。コンパイル時の切り替えをどのように行うのかについては議論されていません。 –

2

aを選択する。コンパイル時のcppファイルはOKで完全に合理的です... の場合無視された.cppファイルはコンパイルされません。これは、プラットフォーム固有の実装を選択する1つの方法です。

しかし、一般的には(できるだけ単純な例のように)、テンプレートを使用して静的多型を実現する方がよいでしょう。コンパイル時に選択する必要がある場合は、プリプロセッサマクロを使用します。

2つの実装と交差していないが、それでも、指定されたインタフェースため実装されているん別のプロジェクトを参照する場合、私は別の「プロジェクト」として、そのインターフェイスを抽出することをお勧めします。そうすることで、別々のプロジェクトは、インタフェースを提供する3つ目のプロジェクトに依存していても、互いに直接的には関連していません。

0

ご使用のケースでは、ifdef -blocksを使用することをお勧めします。これはコンパイルする前にチェックされます!このメソッドは、同じコードに対して異なるプラットフォーム間を区別するために使用されることもあります。これらのコードで

// Car.cpp 
#include "Car.h" 

#define FERRARI 
//#define FIAT 

#ifdef FERRARI 
string Car::WhatCarAmI() { return "Ferrari"; } 
#endif 

#ifdef FIAT 
string Car::WhatCarAmI() { return "Fiat"; } 
#endif 

のみFERRARIが定義されているので、コンパイラは、フィアットのIFDEF - ブロックを無視します。この方法では、両方の車に必要な方法を引き続き使用できます。異なるものを必要とするすべてのものを、ifdefsに入れて、単に定義を入れ替えることができます。

実際

代わりの定義をスワップアウト、あなたが選択したどのようなビルド構成に応じて、単独であなたのコードを残して -Dビルドスイッチを使用してGCCコマンドライン上の定義を提供、 と思います。

+1

実際には定義を交換する代わりに、あなたのコードをそのままにして、どのビルド構成が選択されたかに応じて、 '-D'ビルドスイッチを使ってGCCコマンドラインに定義を提供します。 –

+0

私はちょうど同様の何かの編集についてでした。あなたの提案はより良いthoです。あなたが好きなら、私の答えにそれを加えることができます。 –

+1

この場合、マクロとifdefは良い考えではないと思います。他に言及されているように:コンパイル時に選択されたファイルまたはテンプレートを使用します。 ifdefは醜いです! – Klaus

関連する問題