使用派生类的数据调用基类的方法:有一种优雅的方法吗?

时间:2014-04-03 19:42:23

标签: c++ inheritance

我正在开发一个C ++库。这个库将包含一堆简单的对象,它们彼此非常相似。

我为我的对象定义了一个简单的界面:

struct ICommand_v1
{
  virtual void GetCommandName(wchar_t* nameBuffer, size_t* nameBufferSize) = 0;
  virtual void GetCommandGUID(wchar_t* guidBuffer, size_t* guidBufferSize) = 0;
  virtual bool Execute(int argc, wchar_t* argv[]) = 0;
};

我的困难在于GetCommandNameGetCommandGUID功能。对于每个子类,它们应该几乎相同;有一些健全性检查,然后返回命令的内置名称或GUID。从一个GetCommandName到另一个{1}}或另一个GetCommandGUID的唯一区别是返回值。我宁愿不在我的库将使用的二十几个对象中复制这些方法,所以我尝试为我的对象创建一个基类:

struct ICommandImplementation_v1: ICommand_v1
{
public:
  virtual void GetCommandName(wchar_t* nameBuffer, size_t* nameBufferSize)
  {
    size_t workingBufferSize = *nameBufferSize;

    if ((nameBuffer == nullptr) || (wcslen(commandName) > workingBufferSize))
    {
      *nameBufferSize = wcslen(commandName);
      return;
    }

    wcsncpy(nameBuffer, commandName, workingBufferSize);
    *nameBufferSize = wcslen(commandName);
  }

  virtual void GetCommandGUID(wchar_t* guidBuffer, size_t* guidBufferSize)
  {
    size_t workingBufferSize = *guidBufferSize;

    if ((guidBuffer == nullptr) || (wcslen(commandGUID) > workingBufferSize))
    {
      *guidBufferSize = wcslen(commandGUID);
      return;
    }

    wcsncpy(guidBuffer, commandGUID, workingBufferSize);
    *guidBufferSize = wcslen(commandGUID);
  }

  virtual bool Execute(int argc, wchar_t* argv[])
  {
    return true;
  }

private:
  const wchar_t* commandName = TEXT("Default");
  const wchar_t* commandGUID = TEXT("Default");
};

然后,我尝试让我的对象覆盖基类的commandNamecommandGUID属性:

struct AboutCommand: ICommandImplementation_v1
{
public:
  bool Execute(int UNUSED(argc), wchar_t* UNUSED(argv[]))
  {
    return true;
  }

private:
  const wchar_t* commandName = TEXT("AboutCommand");
  const wchar_t* commandGUID = TEXT("01eba0e6-81b9-4fa7-a9f3-407d330da9b3");
};

当然,这实际上并没有奏效。创建AboutCommand对象并调用其GetCommandName返回“默认”。这是有道理的 - 我们实际上是在调用ICommandImplementation_v1的{​​{1}},GetCommandName不知道ICommandImplementation_v1或其阴影AboutCommand

此时,我想我可能必须在commandName中创建一个简单的受保护方法,该方法接受命令名称以及缓冲区/缓冲区大小(ICommandImplementation_v1,然后ICommandImplementation_v1::GetRealCommandName(const wchar_t* commandName = TEXT("Default"), wchar_t* nameBuffer, size_t* nameBufferSize)的{​​{1}}只会使用自己的AboutCommand来调用此函数。但这对我来说似乎很笨拙;有没有更干净,更优雅的方法来执行此操作?

2 个答案:

答案 0 :(得分:2)

更简单的方法是将两个字符串作为参数传递给基类:

struct ICommandImplementation_v1: ICommand_v1
{
public:
  ICommandImplementation_v1(wchar_t const* name, wchar_t const* guid):
     commandName(name),
     commandGUID(guid)
  {
  }
  void GetCommandName(wchar_t* nameBuffer, size_t* nameBufferSize)
  {
    size_t workingBufferSize = *nameBufferSize;

    if ((nameBuffer == nullptr) || (wcslen(commandName) > workingBufferSize))
    {
      *nameBufferSize = wcslen(commandName);
      return;
    }

    wcsncpy(nameBuffer, commandName, workingBufferSize);
    *nameBufferSize = wcslen(commandName);
  }

  void GetCommandGUID(wchar_t* guidBuffer, size_t* guidBufferSize)
  {
    size_t workingBufferSize = *guidBufferSize;

    if ((guidBuffer == nullptr) || (wcslen(commandGUID) > workingBufferSize))
    {
      *guidBufferSize = wcslen(commandGUID);
      return;
    }

    wcsncpy(guidBuffer, commandGUID, workingBufferSize);
    *guidBufferSize = wcslen(commandGUID);
  }

  virtual bool Execute(int argc, wchar_t* argv[])
  {
    return true;
  }

private:
  const wchar_t* commandName = TEXT("Default");
  const wchar_t* commandGUID = TEXT("Default");
};

struct AboutCommand: ICommandImplementation_v1
{
public:
  AboutCommand(): 
      ICommandImplementation_v1(TEXT("AboutCommand"), 
                                TEXT("01eba0e6-81b9-4fa7-a9f3-407d330da9b3")) 
  {}

  bool Execute(int UNUSED(argc), wchar_t* UNUSED(argv[]))
  {
    return true;
  }
};

通常,您想要的是"template method"。不要在基本子句中定义两个私有字段,而是定义两个私有纯虚方法,它们被称为GetCommandGUID和GetCommandName,并返回特定于子类的值:

struct ICommandImplementation_v1: ICommand_v1
{
public:
  void GetCommandName(wchar_t* nameBuffer, size_t* nameBufferSize)
  {
    size_t workingBufferSize = *nameBufferSize;

    if ((nameBuffer == nullptr) || (wcslen(commandName()) > workingBufferSize))
    {
      *nameBufferSize = wcslen(commandName());
      return;
    }

    wcsncpy(nameBuffer, commandName(), workingBufferSize);
    *nameBufferSize = wcslen(commandName());
  }

  void GetCommandGUID(wchar_t* guidBuffer, size_t* guidBufferSize)
  {
    size_t workingBufferSize = *guidBufferSize;

    if ((guidBuffer == nullptr) || (wcslen(commandGUID()) > workingBufferSize))
    {
      *guidBufferSize = wcslen(commandGUID());
      return;
    }

    wcsncpy(guidBuffer, commandGUID, workingBufferSize);
    *guidBufferSize = wcslen(commandGUID);
  }

  virtual bool Execute(int argc, wchar_t* argv[])
  {
    return true;
  }

private:
  virtual const wchar_t* commandName() = 0;
  virtual const wchat_t* commandGUID() = 0;
};

struct AboutCommand: ICommandImplementation_v1
{
public:
  bool Execute(int UNUSED(argc), wchar_t* UNUSED(argv[]))
  {
    return true;
  }

private:
  const wchar_t* commandName() {return TEXT("AboutCommand")}
  const wchar_t* commandGUID() {TEXT("01eba0e6-81b9-4fa7-a9f3-407d330da9b3")}
};

请自己帮忙,不要使用wchar_t *但是对字符串使用std :: wstring。

答案 1 :(得分:0)

我能想到的一种方法是使用Virtual Getters

 struct ICommandImplementation_v1: ICommand_v1
 {
  public :
   virtual char * getCommand()
   {
      return commandName;
   }
 }

struct AboutCommand: ICommandImplementation_v1
 {
    public :
     virtual char * getCommand()
       {
          return commmandName; //please take care of memory allocations etc
        }
  .
  .
 }

然后在您使用GetCommandName()的基类ICommandImplementation_v1中的函数commandName内使用this->getCommand()

例如: 替换

  *nameBufferSize = wcslen(commandName);

  *nameBufferSize = wcslen(this->getCommand());    

因此,在运行时,根据底层对象使用正确的commandName。

另外,请阅读静态多态性。我认为它浪费资源来在派生类中存储额外的指针,这是为了同一目的。您所要做的就是更改基类中commandName的值,以便执行以下操作。

class Derived1 : Base<commandName1> {
}

class Derived2 : Base<commandName2> {
}