假设我有一个使用条件编译的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 * )
        {
        }
    }
    

    07-26 00:04
    查看更多