不同构造函数的命令行参数

时间:2016-12-31 11:03:56

标签: c++ constructor abstract-class

假设我有一些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所述的异常)。

1 个答案:

答案 0 :(得分: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;
}