クラスの相互参照 (C++をもう一度)
[履歴] [最終更新] (2016/06/03 22:02:35)
最近の投稿
注目の記事

サンプルコード

クラスのメンバ関数のフレンド登録などを行うためにクラスの相互参照が発生することがあります。このような場合はクラスの不完全型を宣言することで解決します。

my_class.h

#ifndef MY_CLASS_H_20141223_0137_
#define MY_CLASS_H_20141223_0137_

#include "my_friend_class.h" // 「1.」の場合は不完全型 <*↓> で十分なため不要

class MyClass {
    // 関連事項: フレンド関数 https://www.qoosky.io/techs/96234ba04d

    // 1. フレンドクラスを登録する場合
    // (メンバ関数すべてが MyClass の private,protected を閲覧可能)
    // friend class MyFriendClass; // 不完全型の宣言を兼ねる <*>

    // 2. 特定のメンバ関数のみをフレンド登録する場合
    friend MyClass* MyFriendClass::CreateMyClass(int intval) const;

public:
    void Show() const;

private: // コンストラクタ関連、すべて private
    MyClass(int intval);
    MyClass(const MyClass&); // 敢えて cpp で実装しない技 (呼び出すとエラーにできる)
    void operator=(const MyClass&); // (同上)
    int m_intval;
};

#endif // #ifndef MY_CLASS_H_20141223_0137_

my_class.cpp

#include "my_class.h"
#include <iostream>
using namespace std;

MyClass::MyClass(int intval) :
    m_intval(intval)
{
}

void MyClass::Show() const {
    cout << m_intval << endl;
}

my_friend_class.h

#ifndef MY_FRIEND_CLASS_H_20141223_0137_
#define MY_FRIEND_CLASS_H_20141223_0137_

class MyClass; // 不完全型
// こちらで #include "my_class.h" してしまうと、お互いに
// include していることになり、無限 include が発生してエラー
// (ifndef によって無限 include は回避できますが、そうすると
//  "my_class.h" 内で "my_friend_class.h" を事実上 include
//  できずにエラーになることが、少し考えると分かります)
// 不完全型 MyClass の宣言によってこれを回避できます。

class MyFriendClass {
public:
    MyClass* CreateMyClass(int intval) const; // 最低でも不完全型の宣言が必要
                                              // (完全な宣言までは知る必要がない)
};

#include "my_class.h" // エラー回避のため MyFriendClassの完全な宣言の後で include します。
// ちなみにこの include は MyFriendClass の完全な宣言のためではなく my_friend_class.cpp
// における MyFriendClass::CreateMyClass の実装のためです。

#endif // #ifndef MY_FRIEND_CLASS_H_20141223_0137_

my_friend_class.cpp

#include "my_friend_class.h"

MyClass* MyFriendClass::CreateMyClass(int intval) const {
    return new MyClass(intval); // new するためには MyClass 型の完全な宣言が必要
}

main.cpp

#include "my_friend_class.h"
// #include "my_class.h" // ← なくてもよい
#include <iostream>
using namespace std;

int main() {
    MyFriendClass f;
    MyClass* obj = f.CreateMyClass(1);
    obj->Show(); //=> 1
    return 0;
}

Makefile (文法については、こちらを参照してみてください)

CC = g++
CFLAGS = -g -Wall

%.o: %.cpp
    $(CC) $(CFLAGS) -o $@ -c $<

ALL: main.o my_class.o my_friend_class.o
    $(CC) $(CFLAGS) -o main main.o my_class.o my_friend_class.o

my_class.o: my_class.h
my_friend_class.o: my_friend_class.h
関連ページ