以前は面倒で複雑な下準備が必要だったObjective-C++ですが、最近はとても手軽に扱えるようになりました。本記事ではObjective-C++の使い方や概念、注意点について解説します。
目次
Objective-C++とは
Objective-C++はObjective-CとC++を混在させたプログラミング言語です。Objective-C上でC++の構文や機能が利用できる他、C++で書かれた既存のライブラリやコードを活用することも可能となっています。
そもそもObjective-C自体は、C言語にSmalltalk風のオブジェクト指向機構を組み込んだサイボーグ言語として知られていますが、Objective-C++ではこのC言語の代わりにC++が使われる形となっています。
そのためObjective-C++の活用によって、C++にしかない便利な記法や機能をObjective-Cの世界で活用できるようになるというメリットが得られます。
Objective-C++の始め方・使い方
既存のObjective-Cソースファイルの拡張子をmm
に変更するだけで、簡単にObjective-C++が使えるようになります。Xcode側でも、既存のObjective-Cソースファイルの拡張子をm
からmm
に変換するだけで、自動的にObjective-C++ソースとしてコンパイルされるようになります。
ObjCpp.m → ObjCpp.mm
すぐにでもautoによる型推論やif文内での変数初期化、初期化リスト等、C++由来の便利な記法が利用できます。
ObjCpp.mm
#import "ObjCpp.h"
@implementation ObjCpp
+ (void)load {
auto ary = [@"a,b" componentsSeparatedByString:@","];
if (auto last = ary.lastObject) {
puts(last.UTF8String); // "b"
}
[@"123" substringWithRange:{1, 2}]; // @"23"
}
@end
ObjCpp.h
#import <Foundation/Foundation.h>
@interface ObjCpp : NSObject @end
C++関連の処理や宣言は実装ファイル側に書く
基本的にC++関係のコードは実装ファイル側(ObjCpp.mm)に記述します。
ヘッダーファイル側(ObjCpp.h)にC++関係の記述を行ってしまうと、ObjCpp.hを利用する他のソースファイルもObjective-C++ソースとしてコンパイルしなければならなくなるため注意が必要です。
ヘッダファイル側にはあくまで他の純粋なObjective-Cコードとやり取りするためのメソッド/プロパティのみを定義するようにしましょう。
ObjCpp.h
@interface ObjCpp : NSObject
// GOOD
@property NSArray *list;
// BAD: 呼び出し側もObjective-C++ソースでなければならない
// @property std::vector<NSString *> list;
@end
こうすると見かけ上はObjective-Cのヘッダファイルとなるため、他の純Objective-Cソースから利用することが可能になります。
関数/変数の公開方法
Objective-C++で外部宣言された関数や変数をObjective-C側でそのまま使用することはできません。
// ObjC.m
test(); // Undefined symbols for architecture x86_64: "_test", referenced from:
Objective-C++ソース側では、外部宣言時にC言語のリンケージを指定する必要があります(extern "C"
)。
ObjCpp.h
#ifdef __cplusplus
extern "C" void test();
#else
extern void test();
#endif
ObjCpp.cpp
void test() {}
<objc/objc-api.h>
ヘッダーファイルのOBJC_EXTERN
マクロや<Foundation/NSObjCRuntime.h>
, <objc/NSObjCRuntime.h>
ヘッダのFOUNDATION_EXTERN
を借用すれば、上記のプリプロセッサによる分岐は不要になります。
#import <Foundation/Foundation.h>
// #import <objc/objc-api.h> // Foundation.hにより省略可
OBJC_EXTERN void test();
FOUNDATION_EXTERN void tset();
Objective-C++の注意点
Objective-C++ソースではXcodeによるリファクタリングが一部機能しないため注意してください(複数ファイル間でのクラス名・メソッド名一括変換等、とりわけXcode 8以前のIDEに注意)。それ以外はObjective-Cソース編集時とほとんど変わりません。入力補完やシンタックスハイライトも普通に効きます。
ただ型チェックが厳しくなる分、明示的な型キャストが必要になる場合があります。Objective-C++移行時には注意が必要です。
char* s = malloc(1); // ERROR: Cannot initialize a variable of type 'char *' with an rvalue of type 'void *'
char* s = (char*)malloc(1); // OK
char* s = static_cast<char*>(malloc(1)); // OK
関連知識
- Objective-Cのクラスを構造体やC++のクラスで保持する方法【Objective-C++】
- C++のクラスや資産をObjective-Cで活用する【ラップ方法とライフサイクルについて】
- C++のオブジェクトをポインタとして保持する方法【Objective-C++】
- Objective-C++でヘルパー関数を自作する【メソッド名を短くする】
- 【Objective-C++】NSRangeを拡張する【Rangeラッパークラスの作り方】
- 【Objective-C++】NSObjectラッパークラスで快適コーディングを実現する
OCPP
I have a Objective-C
I have a C++
Ahh!
Objective-C++ (OCPP)
まとめ
ただでさえ天使のObjective-CがC++という翼を持って女神になろうとしてる。