为遗留父类创建人工 argv 数组,在构造函数中接受类似 main 的参数

Pta*_*666 1 c++ legacy-code c++11

我正在努力处理遗留代码(已安排重构,但我现在需要使用它),该代码的设备驱动程序旨在接受(argc, argv)其构造函数的参数。我必须使用的基类,目前我无法更改它,如下所示:

class LegacyDriver
{
public:
  LegacyDriver(int argc, char** argv)
  {
    if (argc < 3)
    {
      throw std::runtime_error("nope");
    }
    // some logic with the arguments interpretation
    int var1 = std::stoi(argv[1]);
    int var2 = std::stoi(argv[2]);
    std::cout << "config: " << var1 << ", " << var2 << "\n";
    // etc ...
  }
  virtual ~LegacyDriver() = default;
  // + some public interfaces, not important ...
};
Run Code Online (Sandbox Code Playgroud)

然后我的新驱动程序必须扩展此类,需要以某种方式将该argc, argv参数传递给基类。到目前为止,我的同事们只是在玩:

class MyNewDriver: public LegacyDriver
{
public:
  MyNewDriver(int argc, char** argv): LegacyDriver(argc, argv)
  {}
  ~MyNewDriver() override = default;
};
Run Code Online (Sandbox Code Playgroud)

但这种设计显然是不可持续的(例如难以测试),我想至少为新驱动程序提供一个有意义的构造函数,例如:

  MyNewDriver(int param1, int param2): LegacyDriver(somehowTransformThemIntoArgcArgv)
  {}
Run Code Online (Sandbox Code Playgroud)

我不能MyNewDriver为此使用额外的私有字段,因为必须之前构造父类。我想到了这样的黑客,在全局范围内使用字符串和向量:

namespace {
std::string hackyProgramName = "Driver";
std::string hackyVar1;
std::string hackyVar2;
std::vector<const char*> hackyArgv;
auto constructArgv = [](int var1, int var2)
{
  hackyVar1 = std::to_string(var1);
  hackyVar2 = std::to_string(var2);
  hackyArgv = std::vector<const char*>({hackyProgramName.c_str(), hackyVar1.c_str(), hackyVar2.c_str()});
  return const_cast<char**>(hackyArgv.data());
};
}
class MyNewDriver: public LegacyDriver
{
public:
  MyNewDriver(int argc, char** argv): LegacyDriver(argc, argv)
  {}
  MyNewDriver(int param1, int param2): LegacyDriver(3, constructArgv(param1, param2))
  {}
  ~MyNewDriver() override = default;
};
Run Code Online (Sandbox Code Playgroud)

但它看起来很丑陋,并且argv矢量在我的驱动程序的每个新实例中都失效了。

有一个更好的方法吗?最好使用单个 lambda。

小智 5

因为你必须维护一个有效的argv数组,并且动作是在构造之前完成的LegacyDriver,所以你可以在之前继承一个类。

class PreDriver {
protected:
    PreDriver( int var1, int var2 ) {
        hackyVar1 = std::to_string( var1 );
        hackyVar2 = std::to_string( var2 );
        hackyArgv = std::vector<const char*>{"Driver", hackyVar1.c_str(), hackyVar2.c_str()};
    };
    constexpr int  argc()const     { return 3; }
    char**  argv() { return const_cast<char**>(hackyArgv.data()); }
private:
    std::string hackyVar1;
    std::string hackyVar2;
    std::vector<const char*>  hackyArgv;
};

class MyNewDriver : private PreDriver, public LegacyDriver {
public:
    MyNewDriver( int param1, int param2 ) : PreDriver(param1,param2), LegacyDriver( this->PreDriver::argc(), this->PreDriver::argv() ) {}
    ~MyNewDriver() override = default;
};
Run Code Online (Sandbox Code Playgroud)