1. ホーム
  2. C++

"エラー:不完全なクラス型へのポインタは許可されません。"の前方宣言。

2022-02-13 17:52:11

C++のファイルをコンパイルする際、forward declarationを使用しているため、この問題に遭遇することがあります。

wikiの定義からすると、コンピュータ・プログラミングにおいて、前方宣言とは、まだ完全に定義されていない識別子(データ型、変数、関数などプログラミングを表す実体)を宣言することである。

例えば

ClassA.h

#pragma once

classB;
classClassA
{
public:
	ClassA(void);
	~ClassA(void);
public:
	void Fun(ClassB & classB);
public:
	ClassB * m_classB;
};

ClassA には ClassB * 型のメンバ変数がありますが、ClassB は完全には定義されていないので、ClassB の宣言のみを与えています;,class ClassB は Incompete 型です。

C++では、完全型と不完備型の違いがあります。完全型はコンパイル時にサイズを決定できるが、不完全型はコンパイル時にサイズを決定できない。したがって、Incomplete型は、その型のオブジェクトを定義することはできず、その型へのポインタや参照を定義したり、その型を正式な参照型や戻り型として使用する関数を宣言(定義ではない)するためにのみ使用できる、限られた方法でのみ使用することができるのです。

通常、AとBの2つのクラスを宣言したとします。A.hにBクラスのオブジェクトを定義する必要がある場合、B b;は #include "B.h"; を、BクラスにAクラスのオブジェクトを定義する必要がある場合はA a; に B.h を含めるように縛ります。しかし相互参照といって、インクルードは許されず、ここで前向き宣言が使用されるのです。

上記の例に倣い、完全なコードは以下の通りです。

クラスA.cpp

#include "ClassA.h"
#include "ClassB.h"//because ClassA.h uses the forward declaration of ClassB, ClassB.h needs to be included here to get all the information about ClassB.

ClassA::ClassA(void)
{
}

ClassA::~ClassA(void)
{
}

void ClassA::Fun(ClassB & classB)
{
	m_classB = &classB;
	int v = m_classB-> GetValue();
}


クラスB.h

#pragma once

#include "ClassA.h"

classB
{
public:
	ClassB(void);
	~ClassB(void);
public:
	int GetValue() const { return m_Value; }
	void SetValue(int val) { m_Value = val; }
private:
	int m_Value;
};

クラスB.cpp

#include "ClassB.h"

ClassB::ClassB(void)
{
	m_Value = 123;
}

ClassB::~ClassB(void)
{
}


前方宣言は相互参照のジレンマを解決し、またコンパイル速度をある程度向上させることができます。それが、前方宣言を必要とする主な理由です。