假设我有一个使用条件编译的C++类:
丙型肝炎
namespace NS{
class C {
public:
C(void);
~C(void);
int func( int arg1 );
private:
int memberVar;
}
C.cpp:
#include "C.hpp"
namespace NS{
C::C( void ){ memberVar = 0; }
C::~C( void ) {}
int C::func( int arg1 ){
int retval = 0;
memberVar = arg1;
#ifdef DEV_BUILD
retval = memberVar;
printf( "memberVar was set.\n" );
#endif
return retval;
}
}
(这是一个简化的示例;假设类
C
长几百行,其中一些函数使用条件编译,每个函数使用相同的条件:#ifdef DEV_BUILD。该应用程序是嵌入式系统应用程序,条件是用于区分测试硬件和生产硬件,两者之间有一些差异)有人建议我改为在单独的.cpp文件中实现功能,但是我对最好的方法还是有些困惑。
我的第一个冲动是创建C_dev.cpp和C_prod.cpp,以不同的方式实现
C::func()
,并因此编辑C.cpp:#include "C.hpp"
#ifdef DEV_BUILD
#include "C_dev.cpp"
#else
#include "C_prod.cpp"
#endif
namespace NS{
C::C( void ){ memberVar = 0; }
C::~C( void ) {}
}
...但这是坏风格吗?还是其他问题?
其他限制:
(更新:建议使用单独的文件,但不是必需的。我欢迎其他建议)
最佳答案
要点1:如果在成堆的代码相同的地方分散了数百个微小的更改,请进行条件编译。通常将更易于阅读和维护。
但是,如果您在功能级别细分了差异,则可以在不同的实现文件中拆分不同的功能。通常,我使用操作系统包装器来执行此操作,例如在Linux和Windows上获取目录列表的区别是相当粗糙的。 (注意:此示例已被C++ 17淘汰。)
要点2:不要制作多个标题。这只会使问题复杂化。您想要公开两个实现之间的公共(public)接口(interface)。如果不能,那么您已经迷路了,需要寻找其他路径。制作一个适合所有实现的通用 header 。
对于此答案,所有实现都使用Asker的原始 header C.hpp:
namespace NS{
class C {
public:
C(void);
~C(void);
int func( int arg1 );
private:
int memberVar;
}
我将Asker的示例分为三个cpp文件:一个在所有内部版本中具有通用功能,另一个在实现包含差异的功能时使用。这样,您就不必重复任何绝对不需要重复的功能。
C_common.cpp所有共享功能都在这里
#include "C.hpp"
namespace NS{
C::C( void ){ memberVar = 0; }
C::~C( void ) {}
}
C_debug.cpp:带有调试语句的函数在此处
#include "C.hpp"
namespace NS{
int C::func( int arg1 ){
int retval = 0;
memberVar = arg1;
retval = memberVar;
printf( "memberVar was set.\n" );
return retval;
}
}
C_no_debug.cpp:没有调试语句的函数在这里
#include "C.hpp"
namespace NS{
int C::func( int arg1 ){
memberVar = arg1;
return memberVar;
}
}
链接程序时,始终链接C_common并指定要链接的C_debug和C_no_debug。
有时,您可以通过分解复杂的函数并仅隔离差异,并为差异提供从共享函数中调用的函数,来进一步提高此功能。
C_common.cpp
#include "C.hpp"
namespace NS{
C::C( void ){ memberVar = 0; }
C::~C( void ) {}
int C::func( int arg1 ){
memberVar = arg1;
debugstuff(); // calls the different functionality
return memberVar;
}
}
C_debug.cpp:
#include "C.hpp"
namespace NS{
void debugstuff()
{
printf( "memberVar was set.\n" );
}
}
C_no_debug.cpp:
#include "C.hpp"
namespace NS{
void debugstuff()
{
}
}
这可能会导致缩放比例不佳,因为您可能要完成许多种衬板功能。参见上面的大点1。但是,如果差异的大小恰到好处,那么您可以利用传递函数参数来减少垃圾邮件。在这种情况下,逻辑上的事情就是传递调试字符串。一个打印,另一个丢弃。
C_common.cpp
#include "C.hpp"
namespace NS{
C::C( void ){ memberVar = 0; }
C::~C( void ) {}
int C::func( int arg1 ){
memberVar = arg1;
debugstuff("memberVar was set.\n"); // calls the different functionality
// and tells it what to do!
return memberVar;
}
}
C_debug.cpp:
#include "C.hpp"
namespace NS{
void debugstuff(const char * message)
{
printf( message );
}
}
C_no_debug.cpp:
#include "C.hpp"
namespace NS{
void debugstuff(const char * )
{
}
}