25

次の2つのシナリオを検討してください(質問全体を完成させ、より明確にするために編集しました)

ケース 1: (以下に正しく記載されているようにコンパイルされない)

//B.h
#ifndef B_H
#define B_H
#include "B.h"

class A;

class B { 
        A obj;
        public:
        void printA_thruB();

         };  
#endif

//B.cpp
#include "B.h"
#include <iostream>

void B::printA_thruB(){
        obj.printA();
        }   


//A.h;
#ifndef A_H
#define A_H

#include "A.h"

class A { 
        int a;
        public:
        A();
        void printA();

         };  
#endif   

//A.cpp                           
#include "A.h"                    
#include <iostream>               

A::A(){                           
        a=10;                     
        }                         

void A::printA()                  
{                                 
std::cout<<"A:"<<a<<std::endl;    
}  


//main.cpp
 #include "B.h"
  #include<iostream>
 using namespace std;

 int main()
 {
 B obj;
 obj.printA_thruB();
 }

ケース 2: (唯一の変更...コンパイル エラーなしで動作します)

//B.h

#include "A.h" //Add this line
//class A;     //comment out this line

A.cpp と B.cpp の両方が一緒に準拠していると仮定します。上記の 2 つのシナリオに違いはありますか? ある方法を他の方法よりも優先する理由はありますか?

編集:では、シナリオ1を機能させるにはどうすればよいですか。

4

6 に答える 6

18

前方宣言は、ヘッダー ファイルのインクルードに代わるものではありません。

名前自体が示すように、前方宣言は単なるDeclaration 定義であり、定義ではありません

したがって、コンパイラにそれがクラスであることを宣言し、ここで宣言するだけで、使用するときに定義を提供します。そのため、通常forward declareはヘッダー ファイルと#include.cpp ファイルで、前方宣言されたクラスのメンバーを使用します。

そうすることで、ヘッダーファイルをインクルードしているところに、コンテンツ全体ではなく、クラスの宣言だけが作成されます#included...

しかし、コンパイラがクラスの定義を必要とするとき、それは#included..

したがって、あなたの場合A obj;、の定義が必要なためclass A#include..

私自身、ここで同様の質問をし、別の 同様の質問にも良い答えがあります...

それが役に立てば幸い..

于 2010-09-03T05:18:57.447 に答える
14

ケース1では、B.cppをコンパイルするときに「不完全な型」エラーが発生します。クラスBにはクラスAオブジェクトが含まれているため、クラスAの定義(特にサイズ)は、クラスBの定義の前に完了する必要があります。

または、some_variableをクラスAへのポインターまたは参照にすることを選択できます。その場合、Bhでは前方宣言で十分です。B.cppでAの完全な定義が必要です(実際に使用したと仮定します)。メンバー関数/データ)。

于 2010-09-03T03:15:41.737 に答える
4

相互に参照するクラスがある場合は、前方宣言を使用する必要があります。

//A.h

class B;

class A {
    B* someVar;
}

//B.h
#include <A.h>

class B {
    A* someVar;
}

しかし、あなたがレイアウトした場合、それを行うことには何のメリットもありません。

于 2010-09-03T03:19:35.527 に答える
3

コンパイラのように考えてください。Aの内部を作成するためにB、コンパイラは を作成する方法を知っているA必要があり、それを行う唯一の方法は、完全な定義を持つことです。前方宣言は、クラスAがどのように見えるかを説明せずに、クラスが存在することをコンパイラーに伝えます。これは、ポインターまたは参照を定義するのに十分です。そのポインターまたは参照を使用するときが来ると、完全なクラス定義が必要になります。

于 2010-09-03T04:34:12.003 に答える
2

some_variableをポインターとして表現する場合、インクルードのオーバーヘッドとコンパイル時間の延長を回避するために、可能な限り前方宣言を使用することをお勧めします。

私はすべてベストプラクティスに賛成ですが、優れたコードナビゲーション機能を備えたIDEを使用するのが本当に好きで、少なくともNetbeansでは転送によって問題が発生します。型宣言に移動しようとすると、実際の宣言を含む.hファイルではなく、常に前方に移動します。ナビゲーションを簡単にするために、追加のコンパイル時間を受け入れたいと思います。たぶん、これはNetbeansの問題です:)

..そうそう..質問の右側にある関連する質問を見ると、前方宣言に関する多くの追加情報が見つかります。

于 2010-09-03T03:24:44.637 に答える