混合使用Objective-C,C++和Objective-C++
- #include <string>
- class CppObject
- {
- public:
- void ExampleMethod(const std::string& str);
- // constructor, destructor, other members, etc.
- };
- #import <Foundation/Foundation.h>
- #import "CppObject.h"
- @interface ObjcObject : NSObject {
- CppObject wrapped;
- }
- - (void)exampleMethodWithString:(NSString*)str;
- // other wrapped methods and properties
- @end
然后在ObjcObject.mm中实现这些方法。不过,此时会在两个头文件(ObjcObject.h&CppObject.h)中得到一个预处理和编译错误。问题出在#include和#import上。对于预处理器而言,它只做文本的替换操作。所以#include和#import本质上就是递归地复制和粘贴引用文件的内容。这个例子中,使用#import "ObjcObject.h"等价于插入如下代码:
- // [首先是大量Foundation/Foundation.h中的代码]
- // [无法包含<string>],因为它仅存在于C++模式的include path中
- class CppObject
- {
- public:
- void ExampleMethod(const std::string& str);
- // constructor, destructor, other members, etc.
- };
- @interface ObjcObject : NSObject {
- CppObject wrapped;
- }
- - (void)exampleMethodWithString:(NSString*)str;
- // other wrapped methods and properties
- @end
- #import "ObjcObject.h"
- @interface ObjcObject () // note the empty parentheses
- - (void)methodWeDontWantInTheHeaderFile;
- @end
- @implementation ObjcObject
- // etc.
GCC也支持这个操作。不过clang还支持添加ivar块,也就是你还可以声明C++类型的实例变量,既可以在class extension中,也可以在@implementation开始的位置。本例中的ObjcObject.h可以被精简为:
- #import <Foundation/Foundation.h>
- @interface ObjcObject : NSObject
- - (void)exampleMethodWithString:(NSString*)str;
- // other wrapped methods and properties
- @end
去掉的部分都移到实现文件的class extension中 (ObjcObject.mm):
- #import "ObjcObject.h"
- #import "CppObject.h"
- @interface ObjcObject () {
- CppObject wrapped;
- }
- @end
- @implementation ObjcObject
- - (void)exampleMethodWithString:(NSString*)str
- {
- // NOTE: str为nil会建立一个空字串,而不是引用一个指向UTF8String空指针.
- std::string cpp_str([str UTF8String], [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
- wrapped.ExampleMethod(cpp_str);
- }
如果我们不需要interface extension来声明额外的属性和方法,ivar块仍然可以放在@implementation开始位置:
- #import "ObjcObject.h"
- #import "CppObject.h"
- @implementation ObjcObject {
- CppObject wrapped;
- }
- - (void)exampleMethodWithString:(NSString*)str
- {
- // NOTE: str为nil会建立一个空字串,而不是引用一个指向UTF8String空指针.
- std::string cpp_str([str UTF8String], [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
- wrapped.ExampleMethod(cpp_str);
- }
- @interface ObjcObject () {
- CppObject* wrapped; // 指针!会在alloc时初始为NULL.
- }
- @end
- @implementation ObjcObject
- - (id)initWithSize:(int)size
- {
- self = [super init];
- if (self)
- {
- wrapped = new CppObject(size);
- if (!wrapped) self = nil;
- }
- return self;
- }
- //...
如果是使用C++异常, 也可以使用 try {...} catch {...}把创建过程封装起来. 相应地,还要显式地释放封闭对象:
- - (void)dealloc
- {
- delete wrapped;
- [super dealloc]; // 如果使用了ARC,这句就要略去
- }
作者接着提到了另一个方法,显示分配一块内存,然后在它的基础上调用new来创建对象。首先声明char wrapped_mem[sizeof(CppObject)]; 再使用wrapped = new(wrapped_mem) CppObject();创建了实例wrapped。释放时if (wrapped) wrapped->~CppObject(); 这样虽然可行,但不建议使用。
- #import <Foundation/Foundation.h>
- @interface ABCWidget
- - (void)init;
- - (void)reticulate;
- // etc.
- @end
这样的类定义在Objective-C++中是没有问题的,但在纯C++的代码是不允许的:
- #import "ABCWidget.h"
- namespace abc
- {
- class Widget
- {
- ABCWidget* wrapped;
- public:
- Widget();
- ~Widget();
- void Reticulate();
- };
- }
一个纯粹的C++编译器在Foundation.h中的代码和ABCWidget声明位置出错。
- namespace abc
- {
- struct WidgetImpl;
- class Widget
- {
- WidgetImpl* impl;
- public:
- Widget();
- ~Widget();
- void Reticulate();
- };
- }
然后在Widget.mm中:
- #include "Widget.hpp"
- #import "ABCWidget.h"
- namespace abc
- {
- struct WidgetImpl
- {
- ABCWidget* wrapped;
- };
- Widget::Widget() :
- impl(new WidgetImpl)
- {
- impl->wrapped = [[ABCWidget alloc] init];
- }
- Widget::~Widget()
- {
- if (impl)
- [impl->wrapped release];
- delete impl;
- }
- void Widget::Reticulate()
- {
- [impl->wrapped reticulate];
- }
- }
- #include <objc/objc-runtime.h>
- namespace abc
- {
- class Widget
- {
- id /* ABCWidget* */ wrapped;
- public:
- Widget();
- ~Widget();
- void Reticulate();
- };
- }
不建议向id对象直接发送消息。这样你会失去很多编译器的检查机制,特别是对于不同类中有着相同selector名字的不同方法时。所以:
- #include "Widget.hpp"
- #import "ABCWidget.h"
- namespace abc
- {
- Widget::Widget() :
- wrapped([[ABCWidget alloc] init])
- {
- }
- Widget::~Widget()
- {
- [(ABCWidget*)impl release];
- }
- void Widget::Reticulate()
- {
- [(ABCWidget*)impl reticulate];
- }
- }
像这样的类型转换很容易在代码中隐藏错误,再尝试一个更好的方式。在头文件中:
- #ifdef __OBJC__
- @class ABCWidget;
- #else
- typedef struct objc_object ABCWidget;
- #endif
- namespace abc
- {
- class Widget
- {
- ABCWidget* wrapped;
- public:
- Widget();
- ~Widget();
- void Reticulate();
- };
- }
如果这个头文件被一个mm文件引用,编译器可以充分识别到正确的类。 如果是在纯C++模式中引用,ABCWidget*是一个等价的id类型:定义为typedef struct objc_object* id; 。 #ifdef块还可以被进一步放到一个可重用的宏中:
- #ifdef __OBJC__
- #define OBJC_CLASS(name) @class name
- #else
- #define OBJC_CLASS(name) typedef struct objc_object name
- #endif
混合使用Objective-C,C++和Objective-C++相关推荐
- Objective C范型
范型 范型编程是一种程序语言设计范式,它允许程序员在使用强类型的语言编写代码的时候,延迟确定具体的类型. 以Swift代码为例,假如有一个需求是要交换两个int,很容易写出类似代码 func swap ...
- Paper:《Distilling the Knowledge in a Neural Network神经网络中的知识蒸馏》翻译与解读
Paper:<Distilling the Knowledge in a Neural Network神经网络中的知识蒸馏>翻译与解读 目录 <Distilling the Know ...
- 如何在企业推行OKR?
对于许多小型企业来说,SaaS是采用先进技术的最好途径,它消除了企业购买.构建和维护基础设施和应用程序的需要. SaaS不仅减少了或取消了传统的软件授权费用,而且厂商将应用软件部署在统一的服务器上,免 ...
- ICLR2020 | StructBERT : 融合语言结构的BERT模型
今天给大家介绍阿里巴巴达摩院在ICLR2020的一篇论文,该研究针对预训练语言模型BERT在预训练任务中忽略了语言结构的问题,作者对BERT进行扩展,通过加入语言结构到预训练任务中,其核心思想是在预训 ...
- Object-C与Swift混合开发
Object-C作为Apple的iOS App开发语言服务了很多个年头,2014年Apple推出了新的编程语言Swift.更高效更安全的口号再次吸引了一大批非iOS开发程序猿进入,小编觉得Swift代 ...
- python下载安装教程mac-教程|如何在mac上为Python安装XGBoost!
原标题:教程|如何在mac上为Python安装XGBoost! 摘要:XGBoost是一个开发非常快速和准确的梯度增强模型的库,它在Kaggle数据科学竞赛中被大量的kaggle选手选用,其中包括两个 ...
- MATLAB应用实战系列NSGA-II多目标优化算法原理及应用实例(附MATLAB代码)
前言 NSGA-Ⅱ是最流行的多目标遗传算法之一,它降低了非劣排序遗传算法的复杂性,具有运行速度快,解集的收敛性好的优点,成为其他多目标优化算法性能的基准. NSGA-Ⅱ算法是 Srinivas 和 D ...
- ML之RFXGBoost:基于RF/XGBoost(均+5f-CrVa)算法对Titanic(泰坦尼克号)数据集进行二分类预测(乘客是否生还)
ML之RF&XGBoost:基于RF/XGBoost(均+5f-CrVa)算法对Titanic(泰坦尼克号)数据集进行二分类预测(乘客是否生还) 目录 输出结果 比赛结果 设计思路 核心代码 ...
- ML之RFXGBoost:分别基于RF随机森林、XGBoost算法对Titanic(泰坦尼克号)数据集进行二分类预测(乘客是否生还)
ML之RF&XGBoost:分别基于RF随机森林.XGBoost算法对Titanic(泰坦尼克号)数据集进行二分类预测(乘客是否生还) 目录 输出结果 设计思路 核心代码 输出结果 设计思路 ...
- ML之Xgboost:利用Xgboost模型对数据集(比马印第安人糖尿病)进行二分类预测(5年内是否患糖尿病)
ML之Xgboost:利用Xgboost模型对数据集(比马印第安人糖尿病)进行二分类预测(5年内是否患糖尿病) 目录 输出结果 设计思路 核心代码 输出结果 X_train内容: [[ 3. 102. ...
最新文章
- OvS、OvS-DPDK、VPP 基准性能对比
- Linux cp命令 拷贝文件
- SM_INTEGRATION_SRV
- 是时候抛弃Java 7 – JBoss EAP 6.4了!
- react学习(15)-getTime selectedRowKeys是this.props取值的
- “一张图”解释特色小镇发展历程
- 有哪些送给20多岁年轻人的建议?
- 美国湾区2016年科技行业就业增长率出现骤降
- 统一沟通-技巧-9-Lync 2010-Outlook 2010-自动配置-1-IT人员
- ffmpeg ffplay ffprobe资料整理
- h5快速制作工具-企业级. 非个人无水印
- html邮件模板美化,设计利器:定制你的炫酷邮件模板
- 局域网内两台电脑无法共享文件问题
- 在word中怎么实现奇数页页眉用本章标题,偶数页用论文标题?
- 亿级流量电商详情页系统实战-1.小型电商网站的商品详情页的页面静态化架构以及其缺陷
- redis数据库的下载安装/免安装版
- Python中的布尔类型
- MobSF移动安全检测框架简述
- 2020海大计算机学院保研名单,中国海洋大学2020年硕士研究生拟录取名单公示 (全日制)...
- JavaSE-利用随机数制作的打怪游戏
热门文章
- php显示图片缩略图,使用ThinkPHP生成缩略图及显示的方法
- 计算机故障按照产生机理来分可分为,维修自测题
- codeblocks哪个字体最舒服_如果给你一百万让你放弃一种美食永远不吃,你会放弃哪个?...
- 小度智能音响拆解 芯片_不拆不快:小度音箱拆解测评
- c语言c判断字符数字,c语言问题求教 利用函数判断字符串中是否全为数字
- 常量表达式不允许函数调用_SQLite特殊索引之表达式索引
- python文本相似度分析_文本相似度分析(基于jieba和gensim)
- ionic3 html调用摄像头,Ionic3项目实战
- android显示多个网络图片不显示,Android显示网络图片实例
- java 调用 rsync_运行rsync时,QProcess不显示任何输出