C/C++宏同时使用{与#if及跨平台Android类编写技术咨询
其实在宏里混用{和#if需要注意预处理阶段的展开顺序,直接嵌套容易出问题,我给你两种靠谱的方案:
方案一:用宏包裹带条件编译的代码块
如果你非要在宏里包含#if,可以用反斜杠保持宏的换行连续性,让预处理阶段能正确识别内部的#if指令。比如:#define ANDROID_CODE_BLOCK() \ { \ #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID \ // 这里写你的Android专属代码 \ LOGD("Running on Android"); \ #endif \ }调用的时候直接在函数里写
ANDROID_CODE_BLOCK();就行,宏展开后里面的#if会被二次预处理。方案二:用条件宏定义不同的代码块
这种方式更清晰,避免宏里嵌套预处理指令的混乱。先根据平台定义宏:#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID #define PLATFORM_SPECIFIC_BLOCK() { /* Android代码 */ } #else #define PLATFORM_SPECIFIC_BLOCK() { /* 空实现或其他平台代码 */ } #endif然后在函数里直接用这个宏,完全不用再写
#if:GooglePlayManager::GooglePlayManager() { PLATFORM_SPECIFIC_BLOCK(); }
#if CC_TARGET_PLATFORM代码块 每个函数里都写一遍#if确实很繁琐,我给你几个实用的优化思路,按推荐程度排序:
最推荐:文件级别的平台分离
把Android专属的代码单独放到一个实现文件里,比如GooglePlayManager_Android.cpp,里面写所有Android相关的函数实现;再写一个GooglePlayManager_Windows.cpp,里面是空实现或者占位代码。然后在Visual Studio的Windows项目里只添加Windows版本的实现文件,Android编译时只添加Android版本的文件。这样你在VS里编辑时,完全看不到Android代码的条件编译,而且代码结构更清晰,不同平台的实现彻底隔离。用宏批量包裹函数实现
定义一个宏,自动帮你处理平台条件:#ifdef CC_PLATFORM_ANDROID #define ANDROID_FUNC(ret, name, params, body) \ ret GooglePlayManager::name params body #else #define ANDROID_FUNC(ret, name, params, body) \ ret GooglePlayManager::name params {} #endif然后写函数的时候直接用这个宏,不用手动加
#if:ANDROID_FUNC(void, GooglePlayManager, (), { // 这里直接写Android专属代码,不用包#if initGPGSDK(); }) ANDROID_FUNC(bool, unlockAchievement, (const std::string& id), { return gpg::Achievements().Unlock(id); })全局包裹整个实现文件
如果你的GooglePlayManager类全是Android专属代码,那干脆在整个实现文件的开头和结尾加平台判断:#ifdef CC_PLATFORM_ANDROID // 所有函数的实现都写在这里,不用每个函数里加#if GooglePlayManager::GooglePlayManager() { // Android代码 } GooglePlayManager::~GooglePlayManager() { // Android代码 } // ...其他函数 #else // Windows下的空实现 GooglePlayManager::GooglePlayManager() {} GooglePlayManager::~GooglePlayManager() {} // ...其他空函数 #endif这样整个文件只有一层条件编译,比每个函数里写清爽多了。
接口分离+工厂模式
定义一个纯虚基类IGooglePlayManager,然后分别写AndroidGooglePlayManager和WindowsGooglePlayManager实现这个接口。再写一个工厂函数,根据平台返回对应的实例:class IGooglePlayManager { public: virtual ~IGooglePlayManager() = default; virtual void init() = 0; virtual bool unlockAchievement(const std::string& id) = 0; }; // Android实现 #ifdef CC_PLATFORM_ANDROID class AndroidGooglePlayManager : public IGooglePlayManager { // 实现所有接口 void init() override { /* Android初始化代码 */ } bool unlockAchievement(const std::string& id) override { return gpg::Achievements().Unlock(id); } }; #endif // Windows空实现 #ifdef CC_PLATFORM_WINDOWS class WindowsGooglePlayManager : public IGooglePlayManager { void init() override {} bool unlockAchievement(const std::string&) override { return false; } }; #endif // 工厂函数 std::unique_ptr<IGooglePlayManager> createGooglePlayManager() { #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID return std::make_unique<AndroidGooglePlayManager>(); #else return std::make_unique<WindowsGooglePlayManager>(); #endif }这种方式适合大型项目,代码解耦性最好,后期扩展其他平台也方便。
内容的提问来源于stack exchange,提问作者user8145466

