1

名前空間でクラスを前方宣言するにはどうすればよいですか。たとえば、以下はライブラリのヘッダーファイルであり、ユーザーはプライベートmyPtrについて知る必要がないため、以下のヘッダーファイルをインクルードするときにブーストヘッダーをインクルードする必要はありません。では、boost :: shared_ptrを前方宣言して、ユーザーコードのコンパイルを有効にするにはどうすればよいですか?

MyClass.h

class MyClass
{

private:

  boost::shared_ptr<Mytype> myPtr;

}
4

1 に答える 1

2

TL;DRここにはを含める<boost/shared_ptr.hpp>必要があります。それを回避する(インテリジェントな)方法はありません。MyTypeただし、それ自体は前方宣言できます。

もちろん、#include <boost/shared_ptr.hpp>ユーザーが自分で行う必要がないように、ヘッダーの先頭に書き込むこともできます。実際には、自律的なヘッダー (つまり、エラーなしで最初に含めることができるヘッダー) を提供することをお勧めします。


フォワード コンパイルに関するルールは少し複雑です。すべてのケースを暗記しようとするよりも、それらについての理由を理解する方が簡単です。

次の 2 つの要因があります。

  • セマンティクス
  • メモリ属性 (サイズと配置)

セマンティクス: オブジェクトのメソッド、属性、または基本クラスにアクセスするには、それらについて知る必要があります。もちろん、コンストラクタ、代入演算子、およびデストラクタが、自動的に生成された場合でもメソッドであることを除けば、当然のことのように思えます。それらを忘れがちです。

メモリ属性: ほとんどの言語とは異なり、C++ は可能な限り効率的にしようとします。つまり、オブジェクトをどこかに割り当てるのではなく、その場でオブジェクトにメモリを割り当て使用するように指示しない限り、使用時点でポインタを使用します。もちろんそうです(ポインタまたは参照のいずれかを使用して)。どれだけ割り当てるかを知るために、コンパイラはオブジェクトの内部、つまりフードの下にあるものを確認する必要があります。これは、正確な詳細にアクセスできない場合でも ( private/などprotected)、それらを表示する必要があるため、8 バイト境界に配置された 24 バイトが必要であることを確認できることを意味します (shared_ptrちなみに関係ありません)。

標準では、これら 2 つのニーズ (メソッドとメモリ レイアウト) のいずれかのためにオブジェクトの定義が必要であると言います。定義が必要な場合は、明らかに利用可能でなければなりません。


さて、原因がわかったところで、いろいろチェックしていきます。次の場合に定義が必要です。

  • sizeofまたはalignof?の引数としてオブジェクトを使用する はい(明らかに、メモリ属性が必要です)
  • オブジェクトを属性として使用していますか? はい(メモリー属性が必要)
  • オブジェクトを静的属性として使用していますか? いいえ(1)
  • オブジェクトへのポインタまたは参照を属性として使用していますか? いいえ(2)
  • 関数宣言でオブジェクトを引数として使用していますか? いいえ(3)
  • 関数宣言で戻り値の型としてオブジェクトを使用していますか? いいえ(3)
  • オブジェクトへのポインターまたは参照を渡しますか? いいえ(4)
  • ベースクラスへのキャスト?はい(基本クラスの存在とアクセシビリティのセマンティック チェック)
  • 別のタイプに変換しますか?依存する(5)

(1) 宣言には何も必要ありませんが、静的属性の定義にはオブジェクトの定義が必要です。

(2) ポインターは、オブジェクトとは関係なく、32 ビットまたは 64 ビットの大きさ (コンパイル方法に応じて、...) のいずれかです。参照には実装定義の表現があります。

(3) 値で取得/返された場合でも! ただし、関数定義 (内部で使用されている場合) または関数呼び出しサイトに必要な場合があります。

(4) もちろん、それを使おうとする (p->foo()またはp.foo()) 場合は、別の話です。

(5) オブジェクトの変換演算子を使用する必要がある場合は、明らかに必要です。それ以外の場合、他の型のコンストラクターを使用すると、関数と同じ規則が適用されます (ただし、他の型の定義が必要です)。

物事がより明確になったことを願っています。

于 2013-01-12T18:25:02.130 に答える