Objective-C ++的缺点
我在Objective-C ++中为iOS编写一个大型项目。 我主要使用Objective-C用于UI和其他Apple API,而C ++用于内部audio处理和其他信息处理。 我想知道自由混合Objective-C和C ++的缺点。
当然,混合两个对象模型有其固有的局限性和潜在的混乱和混乱。 我更好奇如何使用Objective-C ++会影响编译过程,可能遇到的语法错误,可读性问题以及如何避免这些问题,等等。我有兴趣了解您的Objective-C ++经验。一直像你和提示你可能有接近这一点。
ObjC ++function非常强大 – 您可以同时select和混合所需的function,并与C,ObjC和C ++进行交互。 我已经使用了很多年了。 当然,有一些注意事项,很好的意识到它们,所以你可以尽量减less你可能遇到的问题:
汇编
当你开始创build非平凡的程序时,编译时间比ObjC或C ++高得多。
有几种常见的方法来在ObjCtypes中声明C ++types:
- 不透明的types
- 转发声明
- 用智能指针转发声明
- 按价值
我只是将这个视为一个亮点,因为从OP中推断出你对这两种语言都很熟悉。 另外,这是关于ObjC ++的更为公开的主题之一。
鉴于C ++types:
class t_thing { public: int a; };
你有很多方法来声明你的ivars:
不透明types:
@interface MONClass : NSObject { void* thing; } @end
这应该避免。 消除types安全并不好。 两个向前的选项将引入types安全。
此变体与ObjC翻译兼容。
前向声明:
class t_thing; @interface MONClass : NSObject { t_thing* thing; } @end
这比不透明的types更好,但是智能指针更好 – 如果你习惯于编写现代的C ++,那就很明显了。
只要您的C ++types位于全局名称空间中,此变体与ObjC翻译兼容。
使用智能指针的前向声明:
class t_thing; @interface MONClass : NSObject { t_smart_pointer<t_thing> thing; } @end
如果您打算设置转换防火墙(例如使用PIMPL并转发以减less依赖关系),这是最好的。 而且,ObjC对象已经经历了locking和分配,所以分配一个C ++types并不是一件坏事。 如果您有多个声明,您可能更愿意为您的实现创build一个包装types,以减less个人分配。
这个变体与ObjC翻译不兼容。
现在是时候提醒你,你应该启用一个ObjC ++的编译器选项: GCC_OBJC_CALL_CXX_CDTORS
。 当这个标志被设置时会发生什么? 编译器生成隐藏的objc方法,调用你的C ++ ivars的构造函数和析构函数。 如果使用GCC_OBJC_CALL_CXX_CDTORS
C ++ ivars必须是默认可构造的。 如果你不启用这个标志,你必须完全手动构build和破坏你的ivars – 如果你构造了两次或者不覆盖子类的初始化器,那么你就面临着UB。
按价值:
#include "thing.hpp" @interface MONClass : NSObject { t_thing thing; } @end
最高的依赖性。 这是(一般)我select的路线,我对此有些遗憾。 我刚刚移动了一些东西来使用更多的C ++,并使用智能指针(以上略)来减less依赖。
这个变体与ObjC翻译不兼容。
关于现代ObjC编译器的另外一件事情:编译器在二进制文件中列出了C ++types的ivars / structure。 信不信由你,这可以消耗大量的二进制空间。
这里的要点是,程序可以采用多种forms。 您可以混合使用这些技术来减less依赖性,这是引入依赖防火墙的最好的地方之一,因为ObjC是非常dynamic的(它的方法必须在一个转换中导出),并且对象创build需要分配,locking,引入引用计数系统 – 单个对象的初始化时间已经相对较高,并且实现将始终隐藏。
如果你的程序中有很多仍然在ObjC中,并且你想保持这种状态,那么你需要使用在全局命名空间中声明的types或者通过对象工厂销售特化的不透明基types。 就我个人而言,我只是用了太多的C ++,这不是一个理想的select,而且包装实现在全球范围内很快变得令人厌烦。
同时,由于编译时间很长,反之亦然:如果可以将实现的重要部分保留为C ++,那么将节省大量编译时间。 由于这个原因和ARC(下面),你可以通过将原始Appletypes保留为CFtypes来获得很多收益,所以你可以在没有ObjC扩展的情况下继续构buildC ++程序。
句法
我很less有问题, 但我保持我的C + +类非常严格:
- 我默认禁止复制和分配。
- 我很less为C ++types声明自定义运算符。
如果你在C ++中很棒,那么你可以避免这个问题,但是我更喜欢编译器来捕捉我犯的错误。
一个明显的问题是在ObjC消息发送中的C ++范围parsing。 这需要一个空间:
[obj setValue:::func(a)]; // << bad [obj setValue: ::func(a)]; // << good
可读性
我遇到的一个问题是,我从来没有find一个支持ObjC ++语法的代码格式化器。
ObjC消息
-
ObjC消息传递并按值返回:按消息返回C ++types时,需要在消息传递之前检查
nil
。 如果消息对象nil
,则结果将在现代运行时(x86_64和iOS)上归零。 如果您使用该实例,则这是未定义的行为。 -
ObjC消息传递并通过引用返回:在通过引用返回C ++types时,您需要在消息传递之前检查
nil
。 如果消息对象nil
,则结果将是未定义的行为(引用0/NULL
)。
为了克服ObjC消息传递的问题,我通常使用这样的forms:
- (bool)selector:(std::string&)outValue;
对于某些内部错误,返回值为false,成功则为true。
那么你可以安全地写:
if (![obj selector:outString]) { /* bail here */ }
杂记
-
ARC兼容性:ObjC ++不适合ARC。 主要原因是ARC不遵循混合对象模型。 示例:如果您尝试将ObjC成员放入C ++types,编译器将拒绝ARC下的程序。 这不是一个真正的问题,因为使用ObjC ++(假设你也使用SBRM)MRC是很简单的,但是它可能是你程序生命周期中的一个问题。
-
合成属性:您将不得不为C ++types定义属性。
-
外部工具:除了Xcode的工具集之外,很less有能够很好地处理或识别ObjC ++的程序。 文本编辑器,IDE,实用程序。
-
Apple的工具:在Xcode的实用程序中,Xcode对ObjC ++的支持有点低。 重构(不可用),导航(改进与clang分析器),概述(是相当原始的),ObjC ++可以中断IB的公用事业,项目升级往往不被支持。