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