对于不同的构造

问题描述:

的命令行参数让我们假设我有一些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

你可以做这样的事情是通用:

// 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