コンピュータプログラミングにおいて、不透明ポインタは不透明データ型の特殊なケースであり、不透明データ型とは、何らかの未指定型のレコードまたはデータ構造へのポインタとして宣言されたデータ型のことである。
ポインタが実装されている言語が厳密な型付け言語である場合、不透明なポインタ型Tに関する他の情報を持たないプログラムやプロシージャでも、型Tの変数、配列、レコードフィールドを宣言したり、その型の値を代入したり、それらの値が等しいかどうかを比較したりすることは可能です。ただし、そのようなポインタを逆参照することはできず、不足している情報を持つプロシージャを呼び出すことによってのみ、オブジェクトの内容を変更することができます。
不透明ポインタは、インターフェースの実装の詳細を通常のクライアントから隠蔽する方法であり、実装を変更しても、それを使用するモジュールを再コンパイルする必要がありません。これは、シンプルなインターフェースを作成し、ほとんどの詳細を別のファイルに隠蔽できるため、プログラマにもメリットがあります。[ 1 ]これは、たとえば共有ライブラリの異なるバージョン間でバイナリコードの互換性を提供する上で重要です。
この手法は、デザインパターンではブリッジパターンとして説明されています。特にC++コミュニティでは、「ハンドルクラス」[ 2 ] 、 「Pimplイディオム」(「ポインタ実装イディオム」の略)[ 3 ] 、 「コンパイラファイアウォールイディオム」[ 4 ] 、 「dポインタ」または「チェシャ猫」 [ 2]などと呼ばれることもあります。Qt[5]やKDE [ 6 ]ライブラリで広く使用されています。
パッケージLibrary_Interfaceは型Handleは限定プライベートです。-- 業務...private type Hidden_Implementation ; -- パッケージ本体で定義type Handle is access Hidden_Implementation ; end Library_Interface ;この型はHandle、仕様では定義されていない実際の実装への不透明なポインタです。この型は、クライアントが型に直接アクセスすることを禁止し、操作を介してのみアクセスできるようにするため、プライベートであるだけでなく、データ構造のコピーを回避し、ダングリング参照を防止するため、制限されていることに注意してください。
パッケージ本体のLibrary_Interfaceはtype Hidden_Implementation is record ... -- 実際の実装は何でも構いませんend record ;-- 操作の定義...ライブラリインターフェース終了;これらのタイプは、 Ada 95 の主任デザイナーであるタッカー・タフトにちなんで「タフトタイプ」と呼ばれることもあります。これは、Ada 83のいわゆる「タフト修正」で導入されたためです。[ 7 ]
Integer.h内:
#pragma oncetypedef struct Integer Integer ;/* * コンパイラは struct obj を不完全型とみなします。不完全型は宣言で使用できます。*/size_t integerSize ( void );void integerSetValue ( Integer * , int );int integerGetValue ( Integer * );Integer.c内:
#include "Integer.h"typedef struct Integer { int value ; } Integer ;/* * 呼び出し元がメモリ割り当てを処理します。* 必要な情報のみを提供してください。 */size_t integerSize ( void ) { return sizeof ( Integer ); }void integerSetValue ( Integer * i , int val ) { i -> value = val ; }int integerGetValue ( Integer * i ) { return i -> value ; }この例は、C言語を使用してオブジェクト指向プログラミングの情報隠蔽(カプセル化)を実現する方法を示しています。 の定義を変更したい場合、 APIも変更しない限り、ヘッダーファイルを使用するプログラム内の他のモジュールを再コンパイルする必要はありません。関数が渡されたポインタが でないことを確認することが望ましい場合もありますが、簡潔にするために上記ではそのようなチェックは省略されています。struct IntegerInteger.hNULL
MyClass.cppm内:
export module org.example.MyClass ;import std ;std :: unique_ptrを使用します。export namespace org :: example {class MyClass { private : struct IntPair ; // ここでは定義されていませんunique_ptr < IntPair > ptr ; // 不透明ポインタpublic : MyClass (); // コンストラクタMyClass ( const MyClass & ); // コピーコンストラクタMyClass ( MyClass && ); //ムーブコンストラクタMyClass & operator = ( const MyClass & ); // コピー代入演算子MyClass & operator = ( MyClass && ); // ムーブ代入演算子~ MyClass (); // デストラクタ// その他の操作... };}MyClass.cpp内:
モジュールorg.example.MyClass ;namespace org :: example {struct MyClass :: IntPair { int a ; int b ; };MyClass :: MyClass () : ptr { std :: make_unique < IntPair > ()} {}MyClass :: MyClass ( const MyClass & other ) : ptr { std :: make_unique < MyClass > ( * other . ptr )} {}MyClass :: MyClass ( MyClass && other ) = default ;MyClass & MyClass :: operator = ( const MyClass & other ) { * ptr = * other . ptr ; return * this ; }MyClass & MyClass :: operator = ( MyClass && ) = default ;MyClass ::~ MyClass () = default ;}。[リンク先] 初版とほぼ同じ内容のオリジナル記事。最新版は書籍『
Exceptional C++』
(2000年、Addison-Wesley刊)に掲載。
{{cite magazine}}: CS1 maint: url-status (リンク)