2016-12-31 19 views
3

のは、私はいくつかのC++抽象クラスを持っており、そのすべての継承されたクラスが別のコンストラクタを持っているとしましょう:コマンドライン引数

class Abstract{ 
//don't worry, there is some pure virtual method here 
} 

class A : public Abstract { 
public: 
    A (int Afirst, std::string Asecond, int Athird) {...} 
... 
} 

class B : public Abstract { 
public 
    B (double Bfirst, std::int Bsecond) {...} 
... 
} 

class C : public Abstract { 
public 
    C (std::string Cfirst, double Csecond, int Cthird, float Cfourth) {...} 
} 

あなたが見ることができるように、すべての継承されたクラスは、(おそらく)別のコンストラクタを持っています。私はこれを行うための最善の方法がある場合は、疑問に思う例えば、各コンストラクタに直接char *argv[]を通過させ、内部のすべてのチェックを行う

int main (int argc, char *argv[]){ 
    if(argc < 2){ 
    std::cerr<<"Too few arguments!"<<std::endl; 
    exit(1); 
    } 
    std::string type = argv[1]; 
    Abstract *abs; 
    if(!type.compare("A"){ 
    if(argc < 5){ 
     std::cerr<<"Too few arguments for A!"<<std::endl; 
     exit(1); 
    } 
    abs = new A(atoi(argv[2]), argv[3], argv[4]); 
    } 
    //similar for B, C, D 
} 

は今、私は、ジェネリックmain()を書くことのような何かをしたいですコンストラクタ(そして最終的にはhereのように例外をスローします)。あなたが一般的なようにそのような何かを行うことが

+3

あなたは引数が与えられたコンストラクタ私見を一致させるかどうかを確認することから抜け出すことはできませんが、私はクラスを汚染しませんチェックコード。私は 'argc'と' argv'をとり、適切なクラスのインスタンスを返すファクトリ関数を書くでしょう。それは、チェックコードが含まれたままになります。 – Unimportant

答えて

2

// functions to convert const char* to given type 
template <typename T> T To(const char*); 

template <> int To(const char* s) { return atoi(s); } 
template <> const char* To(const char* s) { return s; } 
template <> std::string To(const char* s) { return s; } 
// ... 

// Your classes: 
struct Abstract { virtual ~Abstract() = default; }; 

struct A : Abstract { A (int, std::string, int) {}}; 
struct B : Abstract { B (int, int) {}}; 
// ... 

namespace detail 
{  
    // Helper functions for the factory. 
    template <typename T, typename Tuple, std::size_t... Is> 
    std::unique_ptr<Abstract> make_abstract(const char*argv[], std::index_sequence<Is...>) 
    { 
     return std::make_unique<T>(To<std::tuple_element_t<Is, Tuple>>(argv[2 + Is])...); 
    } 

    template <typename T, typename Tuple> 
    std::unique_ptr<Abstract> make_abstract(int argc, const char*argv[]) 
    { 
     constexpr int tuple_size = std::tuple_size<Tuple>::value; 
     if (argc < tuple_size) { 
      throw std::runtime_error("Too few arguments"); 
     } 
     return make_abstract<T, Tuple>(argv, std::make_index_sequence<tuple_size>()); 
    } 
} 

// The public factory 
std::unique_ptr<Abstract> make_abstract(int argc, const char*argv[]) 
{ 
    if (argc == 1) { 
     return nullptr; 
    } 
    const std::string name = argv[1]; 
    if (name == "A") { 
     return detail::make_abstract<A, std::tuple<int, std::string, int>>(argc, argv); 
    } else if (name == "B") { 
     return detail::make_abstract<B, std::tuple<int, int>>(argc, argv); 
    } 
    // ... 
    return nullptr; 
} 
+0

私の編集はどうですか?私はそれを取った[here](http://stackoverflow.com/a/1640765/4480180) – justHelloWorld

+0

@justHelloWorld:それは可能かもしれないが、私はこのサンプルのために私のことを保つことが好きです。通常の文字列の空白。加えて、他の型を 'enum'として拡張する方法を示していると思います。 – Jarod42

+0

コードを説明していただけますか?私の考えで少し進歩しました – justHelloWorld

関連する問題