19

他のファイルをあまり多く含まない適切なヘッダー ファイルを作成して、それらをクリーンに保ち、コンパイル時間を短縮しようとしています。

これを行っているときに2つの問題が発生しました。

  1. 基本クラスの前方宣言は機能しません。

    class B;
    
    class A : public B
    {
    
        // ...
    }
    
  2. STD クラスの前方宣言が機能しません。

    namespace std
    {
        class string;
    }
    
    class A
    {
        string aStringToTest;
    }
    

これらの問題を解決するにはどうすればよいですか?

4

6 に答える 6

28

解決できない最初の問題。

2 番目の問題は、標準ライブラリ クラスとは関係ありません。これは、クラスのインスタンスを独自のクラスのメンバーとして宣言するためです。

両方の問題は、コンパイラがクラスの定義からクラスの合計サイズを見つけられなければならないという要件によるものです。

ただし、コンパイラは、クラスの完全な定義がまだない場合でも、クラスへのポインターのサイズを計算できます。したがって、このような場合に考えられる解決策は、消費するクラスにポインター (または参照) メンバーを含めることです。

「is a」関係が得られないため、基本クラスのケースではあまり役に立ちません。

のようなことをする価値もありませんstd::string。第一に、文字バッファーの便利なラッパーであり、非常に単純なものでメモリ管理を行う必要がありません。ヘッダーを含めないようにするために、それへのポインターを保持している場合は、おそらく良いアイデアを取りすぎています。

第二に(コメントで指摘されているように)、std::stringへの typedefstd::basic_string<char>です。そのため、代わりにそれを前方宣言 (および使用) する必要があります。その時点までに、物事は非常に曖昧になり、読みにくくなります。これは別の種類のコストです。それは本当に価値がありますか?

于 2008-12-23T20:16:46.010 に答える
7

Earwicker が以前に回答したように、コンパイラはクラスのサイズを知る必要があるため、これらのケースでは前方宣言を使用できません。

前方宣言は一連の操作でのみ使用できます。

  • 前方宣言されたクラスをパラメーターとして受け取るか、それを返す宣言関数
  • 前方宣言されたクラスへのメンバー ポインターまたは参照の宣言
  • クラス定義で前方宣言型の静的変数を宣言する

あなたはそれを使用することはできません

  • 指定された型のメンバー属性を宣言します (コンパイラにはサイズが必要です)
  • タイプのオブジェクトを定義または作成するか、削除します
  • クラスの任意の静的メソッドまたはメンバー メソッドを呼び出すか、任意のメンバーまたは静的属性にアクセスします

(私は何かを忘れましたか?)

auto_ptranの宣言は生のポインターの宣言と同じではないことを考慮してauto_ptrください。これは、ポインターがスコープ外になるとインスタンス化によってポインターが削除され、削除するには型の完全な宣言が必要になるためです。in を使用しauto_ptrて前方宣言された型を保持する場合は、(空の場合でも) デストラクタを提供し、完全なクラス宣言が表示された後に定義する必要があります。

他にもいくつかの微妙な点があります。クラスを前方宣言すると、それがクラスになることをコンパイラに伝えます。これは、別の型に anenumまたは aを指定できないことを意味します。これは、テンプレートの特定のインスタンス化の typedef であるため、typedefdeclare を転送しようとしたときに発生する問題です。std::string

typedef basic_string<char> string; // aproximate

文字列を前方宣言するには、basic_stringテンプレートを前方宣言してからtypedef. 問題は、テンプレートが取るパラメーターの数を標準が述べていないことです。複数のパラメーターをbasic_string取る場合、上記の式がコンパイルされるように、残りのパラメーターにはデフォルトの型が必要であると述べているだけです。これは、テンプレートを前方宣言するための標準的な方法がないことを意味します。

一方、非標準テンプレート (非 STL、つまり非 STL) を前方宣言する場合は、パラメーターの数がわかっている限り、それを行うことができます。

template <typename T, typename U> class Test; // correct
//template <typename T> class Test; // incorrect even if U has a default type

template <typename T, typename U = int> class Test {
   // ...
};

最後に、Roddy からあなたに与えられたアドバイスは次のとおりです。できるだけ多くのことを前向きに宣言しますが、いくつかのことを含める必要があると想定してください。

于 2008-12-23T21:33:29.397 に答える
3

どちらの場合も、コンパイラは型のサイズを知る必要があります。したがって、前方宣言では十分ではありません。基本クラスは、メンバーを追加するか、仮想テーブルを必要とする可能性があります。文字列メンバーでは、STL 文字列クラスのサイズを格納するために、クラスのサイズを大きくする必要があります。

STL クラスの前方宣言は、コンパイルを高速化する明示的なテンプレートのインスタンス化が一般に実装に含まれているため、多くの場合、お勧めできません。

于 2008-12-23T20:15:56.667 に答える
2

あなたは、実際には問題ではない何かを解決しようと懸命に努力しています。必要なヘッダー ファイルを使用し、それらの要件を可能な限り減らします。ただし、失敗する可能性があるため、極端にしようとしないでください。

場合によっては、PIMPL イディオムが役立つことがありますが、ここでは役に立ちません。

于 2008-12-23T20:17:51.030 に答える
1

基本クラスの場合、宣言だけでなく、完全な型定義が必要です。派生型ヘッダーは、基本クラスのヘッダーを #include する必要があります。

std 名前空間のクラスの場合、適切なヘッダー (この場合は <string>) を含めてから、次の 3 つのいずれかを実行する必要があります。

  1. タイプを完全に修飾します: std::string aStringToTest

  2. その型だけに using 宣言を入れます。

  3. std 名前空間の using 宣言を挿入します。

于 2008-12-23T20:20:45.877 に答える
1

> 基底クラスやstlクラスは前方宣言がダメみたいです。

修正... 基底クラスとオブジェクト メンバーの前方宣言は INAPPROPRIATE です。(「駄目」ではなく「当てはまらない」です。)

基底クラスは、別のクラスの基底クラスとして宣言する場合、宣言する必要があります (前方宣言ではありません)。

オブジェクト メンバーは、別のクラスによって、またはパラメーターとして、または戻り値として宣言されている場合は、宣言する必要があります (前方宣言ではありません)。注: 参照渡しまたはポインタ渡しには、その制約はありません。

訂正... STL クラスの前方宣言は、ISO 14882 によると、未定義の動作です。 http://www.gotw.ca/gotw/034.htm

于 2009-03-04T17:01:48.940 に答える