C++ 移行ガイド

移植性の低い解決策

サンの実装している C と C++ の関数リンケージはバイナリ互換です。すべての C++ の実装がこうなっているわけではありませんが、比較的共通のことです。互換性がなくなってもかまわないのであれば、キャストを使って C++ リンケージ関数を C リンケージ関数と同じように使用できます。

たとえば静的メンバー関数がよい例です。リンケージに関する C++ 言語の新しい規則が関数の型の一部となるまでは、クラスの静的メンバー関数を C リンケージを持つ関数として扱うのが一般的でした。これによって、クラスメンバー関数のリンケージを宣言できないという制限を回避していました。たとえば、次の例を考えてみましょう。


// 既存のコード
typedef int (*cfuncptr)(int);
extern“C”void set_callback(cfuncptr);
class T {
    ...
    static int memfunc(int);
};
...
set_callback(T::memfunc); // 新しい規則では無効

上記の問題を解決するには、前の項でお勧めしたように T::memfunc を呼び出す関数ラッパーを作成してから、すべての set_callback 呼び出しを変更して T::memfunc の代りにラッパーを使用します。こうすると、完全な移植性を持つ正しいコードになります。

もう 1 つの解決策として、次の例のように多重定義した set_callback 呼び出しを作成して、C++ リンケージを持つ関数を受け取り、元の関数を呼び出すこともできます。


// 変更したコード
extern“C”{
    typedef int (*cfuncptr)(int); // C 関数へのポインタ
    void set_callback(cfuncptr);
}
typedef int (*cppfuncptr)(int); // C++ 関数へのポインタ
inline void set_callback(cppfuncptr f) // 多重定義したもの
    { set_callback((cfuncptr)f); }
class T {
    ...
    static int memfunc(int);
};
...
set_callback(T::memfunc); // 元のコードと同じ

この例では、既存のコードをわずかに変更しただけです。ここには、コールバックを設定する set_callback を新たに追加しました。既存のコードは元の set_callback を呼び出していましたが、ここでは多重定義したものを呼び出し、それが元のものを呼び出します。多重定義したものはインライン関数なので、実行時のオーバーヘッドはまったくありません。

この方法は Sun C++ では動作しますが、すべての C++ の実装で動作するとは限りません。他のシステムでは、C 関数と C++ 関数の呼び出し順序が異なる場合があるからです。