2014-04-03 28 views
0

我正在研究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到另一个,或一个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返回“Default”。这是有道理的 - 我们实际上调用ICommandImplementation_v1GetCommandName,而ICommandImplementation_v1不知道AboutCommand或其阴影commandName

在这一点上,我想我可能得内ICommandImplementation_v1,需要一个命令名称,以及一个缓冲区/缓冲区大小(ICommandImplementation_v1::GetRealCommandName(const wchar_t* commandName = TEXT("Default"), wchar_t* nameBuffer, size_t* nameBufferSize),然后AboutCommandGetCommandName只需调用创建一个简单的方法保护。拥有自己的commandName这个功能这似乎笨拙对我来说,虽然,有没有更清洁,更优雅的方式来做到这一点

+1

难道你不能声明那些保护而不是私人的字段吗?这应该让你“覆盖”他们 – BlackBear

+0

@BlackBear我只是试图改变数据成员以'ICommandImplementation_v1'和'AboutCommand'保护,但我仍然遇到同样的问题。 – computerfreaker

回答

2

的easiert方法是将两个字符串基类作为参数传递:

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作为字符串。

+0

谢谢。我应该想到使用这个基类的c'tor。我不能使用'std :: wstring',但是,因为这段代码是用于DLL [并且跨DLL边界传递STL类型是一个坏主意](http://stackoverflow.com/questions/22797418/how -DO-I-安全地通的对象,尤其是-STL对象到和从-A-DLL)。 – computerfreaker

0

一个我能想到的办法是使用虚拟吸气剂

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 
     } 
    . 
    . 
} 

然后在基类ICommandImplementation_v1功能GetCommandName()里徘徊无论你正在使用commandName您使用this->getCommand()

例如: 替换

*nameBufferSize = wcslen(commandName); 

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

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

另外,阅读关于静态多态性。我认为它浪费了资源来在派生类中存储额外的指针,这是为了相同的目的。你所要做的就是改变基类中的commandName的值,所以你需要做如下的事情。

class Derived1 : Base<commandName1> { 
} 

class Derived2 : Base<commandName2> { 
} 
相关问题