2016-12-31 50 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) {...} 
} 

正如你可以看到,所有的繼承類有(可能)不同的構造。

現在,我想編寫一個通用main(),是這樣的:

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 
} 

我不知道是否有做到這一點,例如直接char *argv[]傳遞給每一個構造函數,使裏面的所有檢查一個最好的方法構造函數(並最終拋出異常,如描述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

我的編輯怎麼樣?我把它從[這裏](http://stackoverflow.com/a/1640765/4480180) – justHelloWorld

+0

@justHelloWorld:這可能是可能的,但我更喜歡保留我的樣本,因爲它是OP用於轉換,讓普通字符串的空格。另外,我認爲它展示瞭如何將其他類型擴展爲'enum'。 – Jarod42

+0

你能解釋一下代碼嗎?這有點先進的我認爲 – justHelloWorld