Objective-C++ 取扱説明書 〜始め方から使い方、注意点まで〜【完全保存版】

以前は面倒で複雑な下準備が必要だった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

関連知識

OCPP

I have a Objective-C
I have a C++
Ahh!
Objective-C++ (OCPP)

まとめ

ただでさえ天使のObjective-CがC++という翼を持って女神になろうとしてる。

広告