2017-02-02 24 views
0

我有一个C++应用程序,其中main()实例化对象MyApp,然后将该对象传递给ReadConfig函数。如何通过函数指针调用具有不同签名的C++函数

ReadConfig打开一个基于文本的文件,解析它并调用相应的MyApp方法来配置它。

class MyApp 
{ 
private: 

public: 
    void SetRate(uint16_t); 
    void EnableLogging(bool); 
    void SetAddress(uint32_t); 
}; 

我想让维护ReadConfig变得很容易,因为随着新的公共方法被添加到MyApp,它可以像更新表一样简单。我提出了以下解决方案,但我不喜欢它。由于必须确保我将0放在正确的位置,因此很难维护。

下面是我已经能够解决的一个例子。任何建议,使这个更好,将不胜感激。注意我在嵌入式工作,所以我们使用的C++编译器不支持C++ 14 &,这没有任何提升。我想避免使用任何STL库来理解自己做这件事的机制。

以下是我有:

enum ARGTYPE {TBOOL, TUINT16, TUINT32}; 

template<typename TOBJ, typename TARG> 
struct TSetting 
{ 
    void (TOBJ::*FSet)(TARG); 
}; 

template<typename obj> 
struct SETTINGFN 
{ 
    const char      *setting_name; 
    ARGTYPE       Targ; 
    TSetting<obj,bool>    HBool; 
    TSetting<obj,uint16_t>   HUint16; 
    TSetting<obj,uint32_t>   HUint32; 
}; 

SETTINGFN<MyApp> MyAppSettings[] = 
{ 
    "logging" ,TBOOL,  &MyApp::EnableLogging, 0,0,0 
    ,"maxrate" ,TUINT16,  0,0,0,&MyApp::SetRate 
    ,"address" ,TUINT32,  0, &MyApp::SetAddress, 0,0 

}; 
unsigned int MyAppSettings_Count = sizeof(MyAppSettings)/sizeof(SETTINGFN<MyApp>); 

然后,因为我读的配置文件,并解析它,我调用一个函数来处理通过函数指针调用实际MyApp的功能。该功能如下:

bool AppSetting(MyApp &E, TObjnode &node) 
{ 
    bool rval = false; 

    for(unsigned int i=0; i<MyAppSettings_Count && !rval; i++) 
    { 
    if(node.GetName() == MyAppSettings[i].setting_name) 
    { 
     rval = true; 

     switch(MyAppSettings[i].Targ) 
     { 
     case TBOOL: 
      (E.*MyAppSettings[i].HBool.FSet)(node.GetValue().AsBool()); 
     break; 

     case TUINT16: 
      (E.*MyAppSettings[i].HUint16.FSet)(node.GetValue().Value()); 
     break; 

     case TUINT32: 
      (E.*MyAppSettings[i].HUint32.FSet)(node.GetValue().Value()); 
     break; 
     } 
    } 
    } 

    return(rval); 
} 
+0

才算及格的字符串到每个二传手,并让他们拨打特定类型的可重复使用的解析代码?然后所有的制定者可以是相同的类型。接受字符串并调用解析函数和类型安全的setter的蹦床可能会更好。 –

+1

因此......为了避免每次添加新属性/设置器时必须向配置调度例程添加函数调用,每次添加新属性/设置器时都希望更新专有数据结构?对于他自己的,我想... –

+0

我想到了这些,但我希望避免改变当前的功能签名或添加新的 – Eric

回答

2

您设计中的刺是不同的参数类型。

如果参数被抽象为一个结构,那么函数可以简化为一个固定的签名。

通过使用碱的结构,签名和更通用的:

struct Arguments_Base 
{ 
}; 

void SetRate(Arguments_Base& ab); 
void EnableLogging(Arguments_Base& ab); 
void SetAddress(Arguments_Base& ab); 

通过具有均匀的签名,函数指针功能对象可以在表或图中使用,使搜索更容易。搜索引擎应该是通用的,并且取决于数据的大小,以便只需要更改数据(例如表格),而不是搜索引擎。

每组参数都应该从Arguments_Base类派生。该函数然后可以使用基类引用dynamic_cast

参见:工厂设计模式,Visitor设计模式,双重分派

+0

信不信由你,我想到了这一点,但我希望避免改变当前的功能签名或添加新的 - 但这是优雅的。 – Eric

+0

Yuck。 dynamic_cast的。甚至配置文件读取。 – rubenvb

+0

@rubenvb如果基类提供了派生类可以超载的方法,则不需要动态转换。认为NVI设计模式。或者,如果像Ben Voigt所建议的那样,基类可以简单地进行转换,而Arguments_Base则是可以返回值(int,bools等)的String类。 – Eric