我正在开发一个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;
};
我的困难在于GetCommandName
和GetCommandGUID
功能。对于每个子类,它们应该几乎相同;有一些健全性检查,然后返回命令的内置名称或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");
};
然后,我尝试让我的对象覆盖基类的commandName
和commandGUID
属性:
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
来调用此函数。但这对我来说似乎很笨拙;有没有更干净,更优雅的方法来执行此操作?
答案 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> {
}