关于C++和Objective-C混编

Objective-C在大部分情况下足够满足我们的需求,但是还是会有一些情况必须要使用C++,比如:

  1. 使用C++的库
  2. 当Objective-C不够快的时候

第一点自然不必多说,至于第二点,Objective-C的消息机制比起函数调用还是比较慢的,当对性能有极高要求的时候,就需要C/C++来替代。

C++与Objective-C混编只要注意将包含C++代码的.m文件改为.mm即可,XCode就会自动判断该使用何种编译器来编译。

这看起来简单,但实际操作中还是很容易出现令人费解的编译问题,比如最经典的"Unknow type name ‘class’; did you mean ‘Class’?“。究其原因就是我们没有遵守这两条规则:

  • .m文件不能含有C++代码
  • .m文件所import或include的.h文件中不能直接或间接包含C++代码

在保证你的C++代码是正确前提下,如果发现相关编译错误可以通过如下几个方法修复

  1. 将.h文件中的c++代码转移到其他地方
  2. 阻段include或import链
  3. 将相关的.m文件后缀改成.mm

显然第三种方法相对于前两种实施起来更方便,但如果你使用XCode 4以及之后的版本所包含的模板建立项目的话有可能会忽视一个问题:

当你在AppDelegate.h中include或import一个C++的头文件时,当然你一定不会忘记修改AppDelegate.m为AppDelegate.mm,如果只做了这点儿还不够,我们还忽略了隐藏在Supporting Files组内的一个文件的存在–main.m

在以前的XCode模板中main.m默认是这样的

#import <UIKit/UIKit.h>;
 
int main(int argc, char *argv[]) {
 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

而新的模板是这样的:

#import <UIKit/UIKit.h>;
 
#import "AppDelegate.h"
 
int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

看出问题来了吧,main.m新增了#import “AppDelegate.h",这就导致了main.m作为一个Objective-C源文件却引入了C++代码,而Xocde会使用Objective-C的编译器进行编译,从而产生编译错误,因此我们还需要将main.m的后缀改成.mm。

总结+吐槽:我在发现main.m这个问题之前对编译错误纠结了好久,一度修改代码,也一度怀疑是XCode本身的问题(XCode 4出奇的不稳定让人不得不对其产生质疑,虽然这次是我错了),希望同样使用Objective-C++的同学不要像我一样栽在main.m上。

–以上–