C++ 几种特定方法还是一种通用方法?
这是我在这个奇妙的网页上查阅了很长时间后的第一个问题 也许我的问题有点傻,但我想知道其他人对此的看法。更好的做法是,创建几个特定的方法,或者只创建一个泛型方法?这里有一个例子C++ 几种特定方法还是一种通用方法?,c++,C++,这是我在这个奇妙的网页上查阅了很长时间后的第一个问题 也许我的问题有点傻,但我想知道其他人对此的看法。更好的做法是,创建几个特定的方法,或者只创建一个泛型方法?这里有一个例子 unsigned char *Method1(CommandTypeEnum command, ParamsCommand1Struct *params) { if(params == NULL) return NULL; // Construct a string (command) with those specif
unsigned char *Method1(CommandTypeEnum command, ParamsCommand1Struct *params)
{
if(params == NULL) return NULL;
// Construct a string (command) with those specific params (params->element1, ...)
return buffer; // buffer is a member of the class
}
unsigned char *Method2(CommandTypeEnum command, ParamsCommand2Struct *params)
{
...
}
unsigned char *Method3(CommandTypeEnum command, ParamsCommand3Struct *params)
{
...
}
unsigned char *Method4(CommandTypeEnum command, ParamsCommand4Struct *params)
{
...
}
或
我不喜欢后一种选择的主要原因是
ParamsCommand1Struct *value = (ParamsCommand1Struct *) params;
因为“params”不能是指向“ParamsCommand1Struct”的指针,而是指向“ParamsCommand2Struct”或其他人的指针
我真的很感激你的意见 首先,您需要决定使用哪种语言。在这里用
C
和C++
标记问题毫无意义。我假设C++。< /P>
如果您可以创建一个通用函数,那么这当然更可取(为什么您更喜欢多个冗余函数?);你能?但是,您似乎不知道模板。我们需要查看您在此处忽略的内容,以确定模板是否合适:
//用那些特定的参数(参数->元素1,…)构造一个字符串(命令)
在一般情况下,假设模板是合适的,所有这些都会变成:
template <typename T>
unsigned char *Method(CommandTypeEnum command, T *params) {
// more here
}
模板
无符号字符*方法(CommandTypeEnum命令,T*params){
//更多
}
另一方面,如何声明
缓冲区
?是否返回指向动态分配内存的指针?喜欢RAII类型对象,避免动态分配内存,如果是这样。 < P>如果您使用C++,那么我将避免使用Value*,因为您并不需要。拥有多种方法没有什么错。请注意,在第一组示例中,您实际上不必重命名函数-您可以使用不同的参数重载函数,这样每种类型都有一个单独的函数签名。归根结底,这类问题是非常主观的,有很多种方法。查看第一种类型的函数,您可以通过查看模板函数的使用来获得更好的服务,您可以创建一个结构。这就是我用来处理控制台命令的方法
typedef int (* pFunPrintf)(const char*,...);
typedef void (CommandClass::*pKeyFunc)(char *,pFunPrintf);
struct KeyCommand
{
const char * cmd;
unsigned char cmdLen;
pKeyFunc pfun;
const char * Note;
long ID;
};
#define CMD_FORMAT(a) a,(sizeof(a)-1)
static KeyCommand Commands[]=
{
{CMD_FORMAT("one"), &CommandClass::CommandOne, "String Parameter",0},
{CMD_FORMAT("two"), &CommandClass::CommandTwo, "String Parameter",1},
{CMD_FORMAT("three"), &CommandClass::CommandThree, "String Parameter",2},
{CMD_FORMAT("four"), &CommandClass::CommandFour, "String Parameter",3},
};
#define AllCommands sizeof(Commands)/sizeof(KeyCommand)
和解析器函数
void CommandClass::ParseCmd( char* Argcommand )
{
unsigned int x;
for ( x=0;x<AllCommands;x++)
{
if(!memcmp(Commands[x].cmd,Argcommand,Commands[x].cmdLen ))
{
(this->*Commands[x].pfun)(&Argcommand[Commands[x].cmdLen],&::printf);
break;
}
}
if(x==AllCommands)
{
// Unknown command
}
}
void CommandClass::ParseCmd(char*Argcommand)
{
无符号整数x;
对于(x=0;x*命令[x].pfun)(&Argcommand[Commands[x].cmdLen],&::printf);
打破
}
}
if(x==AllCommands)
{
//未知命令
}
}
我使用线程安全的Primtf pPrtuf,所以忽略它。
< P>我不知道你想做什么,但是在C++中,你可能应该从这样的格式化程序基类派生出多个类:class Formatter
{
virtual void Format(unsigned char* buffer, Command command) const = 0;
};
class YourClass
{
public:
void Method(Command command, const Formatter& formatter)
{
formatter.Format(buffer, command);
}
private:
unsigned char* buffer_;
};
int main()
{
//
Params1Formatter formatter(/*...*/);
YourClass yourObject;
yourObject.Method(CommandA, formatter);
// ...
}
这将从类中移除处理所有params内容的责任,并使其成为一个函数。如果在进一步的开发过程中会有新的命令或参数,您不必修改(并最终破坏)现有代码,只需添加实现新功能的新类。一般答案 在本文中,Steve Macguire的建议是在特定情况下使用不同的函数(方法)。原因是您可以断言与特定情况相关的条件,并且您可以更轻松地进行调试,因为您有更多的上下文 一个有趣的例子是用于动态内存分配的标准C运行时函数。大部分都是多余的,因为
realloc
实际上可以做(几乎)你需要的一切。如果您有realloc
,则不需要malloc
或free
。但是当您有这样一个通用函数,用于几种不同类型的操作时,很难添加有用的断言,很难编写单元测试,也很难看到调试时发生了什么。Macquire进一步提出,不仅应该realloc
只做重新分配,还应该有两个不同的功能:一个用于增长块,一个用于收缩块
虽然我大体上同意他的逻辑,但有时使用一种通用方法(通常是在操作高度数据驱动的情况下)具有实际优势。因此,我通常会根据具体情况做出决定,倾向于创建非常具体的方法,而不是过于通用的方法
具体答案
在您的情况下,我认为您需要找到一种方法,从细节中找出通用代码。开关
通常是一个信号,表明您应该使用带有虚拟函数的小型类层次结构
如果您喜欢单一方法方法,那么它可能只是更具体方法的调度器。换句话说,switch语句中的每种情况都只需调用相应的
Method1
、Method2
,等等。如果希望用户只看到通用方法,则可以将特定实现设为私有方法。通常,最好提供单独的函数,因为它们通过原型名称和参数直接和可见地向用户传达可用的信息;这也导致了更直接的文档
我使用多用途函数的一次是用于类似query()函数的功能,其中许多次要的查询函数(而不是导致函数的激增)被捆绑到一个函数中,并带有一个通用的输入和输出void指针
一般来说,考虑一下您正试图通过API原型本身与API用户通信的内容;清楚地了解API可以做什么。他不需要太多的细节;他确实需要知道核心函数,这些函数是API的核心所在。虽然没有完整的答案,但这应该指导您正确的方向:一个函数一个责任。更喜欢只负责一件事并且做得很好的代码
class Formatter
{
virtual void Format(unsigned char* buffer, Command command) const = 0;
};
class YourClass
{
public:
void Method(Command command, const Formatter& formatter)
{
formatter.Format(buffer, command);
}
private:
unsigned char* buffer_;
};
int main()
{
//
Params1Formatter formatter(/*...*/);
YourClass yourObject;
yourObject.Method(CommandA, formatter);
// ...
}