2016-12-31 2 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

Смежные вопросы