インクルードの交差を抑止する方法
出典: YKAwiki
目次 |
[編集]
概要
互いにインクルードしあう形になると、クラスが宣言されていない状態になるためエラーになります。 クラスの仮宣言を使うなどして回避しましょう。
[編集]
問題の例
- Parent
- Child
というクラスを作りたいとします。また、
という条件があるとします。 (たとえば、ChildはParentに従属しており、Parentが親、Childが子という状況を考えます。Childは親へのポインタが欲しいし、Parentは子供を持っていたいわけです。)
コードで書くと
[Parent.h]
#ifndef PARENT
#define PARENT
#include "Child.h"
class Parent{
Child piyo;
};
#endif
[Child.h]
#ifndef CHILD
#define CHILD
#include "Parent.h"
class Child{
void func();
Parent hoge;
};
#endif
となります。#ifndef とかは多重宣言を避けるおまじないです
このとき、
- Parent.hが先に呼ばれ場合
Child.hが呼ばれ、さらにParent.hを呼びますが、すでにPARENTが宣言されるのでスキップされます。するとまだクラスParentが宣言されてないのにメンバ変数Parent hoge;を宣言しようとします。
- Child.hが先に呼ばれた場合
上のことが逆になるだけです。
[編集]
従属関係を整理する方法
Childが親であるParentをメンバクラスに持たせる必要が低ければ、 ヘッダーからはずす事で回避できます。 CPPファイルからならいくら呼んでもかまわないので、 そっちに移すのもよいです。
[Child.h改]
#ifndef CHILD
#define CHILD
class Child{
void func();
};
#endif
[Child.cpp]
#include "Parent.h"
#include "Child.h"
void Child::func(){
Parent hoge;
}
[編集]
クラスの仮宣言を使う方法
上の方式が気に入らない場合は、仮宣言で解決できる場合が多いです。
[Parent.h改] #ifndef PARENT #define PARENT #include "Child.h" class Child;
class Parent{
Child piyo;
};
#endif
[Child.h改] #ifndef CHILD #define CHILD class Parent;
class Child{
void func();
Parent hoge;
};
#endif
注意点として、仮宣言はあくまで「仮」なので、そのままではメンバにアクセスできません。
[編集]
グローバル変数に任せる方法
[Parent.h改]
#ifndef PARENT
#define PARENT
#include "Child.h"
class Parent{
Child piyo;
};
extern Parent *globalParent;
#endif
[Parent.cpp]
#include "Parent.h"
globalParent = new Parent();
[Child.h改]
#ifndef CHILD
#define CHILD
class Child{
void func();
};
#endif
[Child.cpp]
#include "Parent.h"
#include "Child.h"
void Child::func(){
//globalParentを使って色々
}
グローバル変数を使い出すと構成が途端に複雑になるので、シングルトン以外は使わない方がよいです
