C ++での構造体へのポインターの前方宣言
-
08-07-2019 - |
質問
次のような宣言を持つサードパーティのライブラリを使用しています:
typedef struct {} __INTERNAL_DATA, *HandleType;
そして、コンストラクタで HandleType をとるクラスを作成したいと思います:
class Foo
{
Foo(HandleType h);
}
HandleType を定義するヘッダーを含むwithout 。通常、このような型を前方宣言するだけですが、この構文はわかりません。私は本当に次のようなことを言いたいです:
struct *HandleType;
ただし、「*の前に識別子が必要です」と表示されますGCCで。私が見ることができる唯一の解決策は、私のクラスを次のように書くことです:
struct __INTERNAL_DATA;
class Foo
{
Foo(__INTERNAL_DATA *h);
}
ただし、これはライブラリの内部詳細に依存しています。つまり、__ INTERNAL_DATAという名前を使用します。これは実装の詳細です。
__ INTERNAL_DATA(ライブラリの実装の一部)を使用せずに、HandleType(パブリックAPIの一部)を前方宣言することが可能であるように思われます。
編集:探しているものの詳細を追加しました。
解決
更新:
Fooの実装.cppで使用していますが、Fooのヘッダー.hに含めることは避けたいです。たぶん私はあまりにもtoo慢になっているのでしょうか? :)
はい、そうです:)前方宣言を進めます。
HandleTypeがインターフェイスの一部である場合、それを宣言するヘッダーが必要です。そのヘッダーを使用します。
あなたの問題はまだあいまいです。できないものから保護しようとしています。
クライアントライブラリに次の行を追加できます。
typedef struct INTERNAL_DATA *HandleType;
ただし、名前/構造が変更された場合は、キャストの意地悪に陥る可能性があります。
テンプレートを試してください:
template <class T>
class Foo
{
Foo(T h);
};
前方宣言は問題ありません。ポインターまたは参照を使用する場合は、スコープ内でクラス( __ INTERNAL_DATA
)宣言のみが必要です。ただし、メンバー関数またはオブジェクトを使用する場合は、ヘッダーを含める必要があります。
他のヒント
型がサードパーティのライブラリにある場合、前方宣言(ヘッダーの変更による再構築の分離)の大きな利点は事実上失われます。
コンパイル時間を心配している場合(かなり大きなヘッダーです)、プリコンパイル済みヘッダーに配置するか、ライブラリの関連ヘッダーを含めることができます。
E.g。多くのライブラリヘッダーは次のようになります
// library.h
#include "Library/Something.h"
#include "Library/SomethingElse.h"
typedef struct {} __INTERNAL_DATA, *HandleType;
そのように定義されている場合(すべて1行で)、__ INTERNAL DATAは、パブリックインターフェイスのHandleTypeと同じくらいの部分です。
しかし、 __ INTERNAL_DATA
が実際に存在するとは思わない。おそらく、HandleTypeは実際には(内部的に)intです。この奇妙な定義は、intと同じサイズになるように定義する方法ですが、HandleTypeを渡すことになっている場所でintを渡そうとするとコンパイラーがエラーを出すようにします。ライブラリベンダーは、「int」と簡単に定義できます。または&quot; void *&quot;ですが、この方法で何らかの型チェックが行われます。
したがって、 __ INTERNAL_DATA
は単なる慣習であり、変更されることはありません。
UPDATE:上記は少し精神的なげっぷでした... OK、 __ INTERNAL_DATA
は間違いなく存在しません。空の構造体としての定義を見ることができるため、事実としてこれを知っています。サードパーティのライブラリは&quot; C&quot;を使用していると思います。外部リンケージ(名前の管理なし)。この場合、 typedefをコピーするだけです。問題ありません。
ライブラリ自体の内部では、HandleType の定義はまったく異なります。多分 int
、多分&quot; struct MyStruct {.......} *&quot;。
_INTERNAL_DATAを呼び出し元に公開したくない場合は、 typedef void * HandleType を使用するしかありません。次に、ライブラリ内で、* HandleTypeの実装全体を変更するなど、必要な操作を実行できます。
実際のデータにアクセスするためのヘルパー関数を作成するだけです。
inline _INTERNAL_DATA* Impl(HandleType h) {
return static_cast<_INTERNAL_DATA*>(h);
}
あなたが何をしようとしているのかよくわかりませんが、実際のヘッダーファイルを含めなくても以下は動作します:
// foo.h
class Foo
{
public:
template<typename T>Foo(T* h) { /* body of constructor */ }
};
覚えておいてください、コンストラクタの本体内で __ INTERNAL_DATA
のパブリックメンバーにアクセスする必要があります。
編集: James Curranが指摘したように、 __ INTERNAL_DATA
構造体にはメンバーがないため、上記のように問題なく使用できます。