[Swift] Objective-C++とObjective-Cは完全な互換関係ではないみたい

written: kengo

WindowsでC++,iOSでObjective-C(以下ObjC)をそれぞれ触っていましたが、その融合型であるObjective-C++(以下ObjC++)にようやく触れる機会が出たのでちょこっと触った感じを書きます。主にフレームワークとコード互換関係についてです。

ObjCとObjC++ではコンパイラが別

当たり前ですが、まず別のコンパイラで動作します。ObjC++コンパイラではC++とObjCのコードが混在していてもコンパイルすることができます。

#include <stdio.h>
#import <Cocoa/Cocoa.h>

class Cpp
{
public:
    Cpp();
};
 
Cpp::Cpp()
{
    printf("しーぷらぷら");
}
 
@implementation ObjCWrapper
 
+(void) ObjCWrapper
{
    // Cppクラスの実体化
    Cpp cpp;
}
@end

こんな感じでC++のクラスとObjCのクラスが共存できます。C++の記述が.mm内で完結している場合は問題ありません。問題はObjCプレーンとObjC++のファイルが混在した場合にややこしくなります。例えばヘッダを介して次のようなことが起きます(使用環境:XCode6.1 Yosemite)

上記の場合、Hoge.mがObjCpp.hに含まれるC++記述を解釈できずエラーになります。ObjCpp.hをObjCで読む場合、マクロなりで判別する工夫が必要そうです。

ObjC++はObjCのすべてをフォローできるわけではない…らしい?

ObjC++でコンパイルできないものがありました。例としてはNSScreen。これを使っているコードがあったのですがObjC++コンパイラでは、ObjCAPIのリンクで失敗しました(OSX API関数のUndefined Symbol … Architecture x64_86)。(※追記:NSScreenのコンパイルは後日通りました。多分フレームワーク追加の影響?)

ObjC++コンパイラでObjCコンパイラのオブジェクトがリンクできない?

自分はObjCコンパイラで作っておいたライブラリをObjC++の上で使おうとしたのですが、リンクでコケました(ObjCコンパイラで生成したオブジェクトのリンクはOK)。コンパイラが違うので仕方ないかな…とも思いましたが、リンクできる場合もあるみたいでここは要調査(SuperCollider for iOSはそのあたりがうまくできている)。加えて上記のNSScreenのように使えないAPIがあるとすると、ObjCプレーンがApple向け開発においては、やはり正解なのではないかと。

ObjC++を使うなら全面的に使う方がよさそう

ObjC++を使うのであれば、API非互換の危険性はあるものの全面的にObjC++コンパイラで使うのがよさそうという雰囲気です。混在して使うとしてもリンクができる状況を把握しながら使ったほうがよさげです。

Swiftつれづれ(Swift1.1)

このObjC++の流れ、Swiftに似てるなーと思いました。SwiftとObjCをブリッジする際ObjC側でうまくラップしてあげると幸せな感じがするのですけど、ObjC++もきっと同じです。まだ調べ始めたばかりなのでもっとうまくできるのかもしれませんけど。しかし、まるで別言語のようなSwiftのブリッジは、本当によくできてるなー、すごいなー。まぁこれから色々不具合でるでしょうが、また追って報告していきたいと思います。