アプリ版:「スタンプのみでお礼する」機能のリリースについて

C++での内部クラスの宣言の仕方なのですが、例えば、

class Outer
{
private:
   class Inner;
public:
   Outer();
   ~Outer();
};
class Outer::Inner
{
public:
   Inner();
   ~Inner();
};

のように単純に内部クラスが宣言されているだけならば、
その具体的な定義を外側に書くことは可能と思うのですが、

class Outer
{
private:
   class Inner
   {
   public:
      Inner();
      ~Inner();
   };
public:
   Outer();
   ~Outer();

   Inner inner; //内部クラスのインスタンス
};

のように外部クラスが内部クラスのインスタンスを保持していた場合には、
上記のようにインスタンス作成より上で外部クラスの宣言内に内部クラスの定義を書かないと、
コンパイルが通らない(VC++2008)と思います。具体的な中身がないままインスタンスを
作っているのでエラーを吐く理由もわからないでもないですが、
見易さ的に上の例のようにかけないのかなとも思ったりします。

インスタンスを外部クラスに持たせずともどうとでもなるのですが、
あえて上のようなことをしたくなった場合には下のような方法で記述する以外ないのでしょうか?

A 回答 (3件)

見やすさ、というよりは、ヘッダの記述量や変更回数を減らしてコンパイル時間を短縮するために前方宣言を使うことはあります。

その際、値型でなくポインタ型を使うことになります。


class Outer
{
public:
Outer();
~Outer();
private:
class Inner;
Inner* m_pInner;
};

// 以下はヘッダでなく実装ファイルに記述する。
class Outer::Inner
{
public:
Inner();
~Inner();
};

Outer::Outer()
: m_pInner()
{
m_pInner = new Outer::Inner();
}

Outer::~Outer()
{
delete m_pInner;
}


スタック(値型)でなくnewヒープを使うことで、いくぶん効率は低下します。また、ヒープの解放忘れといったヒープ特有のバグが混入しないように気をつける必要があります。

Innerの詳細が分からない段階で値型として埋め込むことができないのは、コンパイラにとってOuterの定義に必要なsizeof(Inner)の計算が実行できないからです。ポインタであればInnerがどのような型であれsizeof(Inner*)は常に一定(ILP32で4バイト、LP64/LLP64で8バイト)のため、前方宣言さえあればOuterは定義できることになります。
    • good
    • 0
この回答へのお礼

すみません。悩んでいたら質問をしたのを忘れてしまいました…。
確かにポインタで確保すればメモリを確保できるのですが、
>スタック(値型)でなくnewヒープを使うことで、いくぶん効率は低下します
を回避するために直接値で保持できないのかなと思いましたが無理みたいですね。

お礼日時:2011/03/16 03:05

手元にコンパイラがないのでできなかったごめんなさい。



class Outer:
class Outer::Inner;

class Outer
{
public:
Outer(void){; }
virtual ~Outer(void){ ; }
private:
Inner Inner;
}

class Outer::Inner
{
private:
Inner(void){ ; }
virtual Inner(void){ ; }
protected:
Inner(const inner &in){ ; }
}

って感じに、プロトタイプ的なものを宣言してあげればすむと思うけれど
個人的には、 へんなことせず、使う順に宣言されていた方がわかりやすいと思いますよ。
# つまり、後者(?)の書き方。

ちなみに、 コンストラクタでは、代入以外しないほうがいいです。
とくに、メモリ確保などは失敗したときのハンドリングができないので異常系処理が面倒になります。

たぶんやるなら

class Inner
{
}

class Outer
{
public:
Outer(inner &in) : inner(in) { ; }
private:
Inner &inner
}
とかじゃなかったかな?
こうすると Innerを多態できるおまけ付きです。
    • good
    • 0

以下のようにすれば、クラス定義を外側に書くどころか、内部クラスの実装を晒さずに済ませることが出来ます。


--- Outer.h ---
class Outer
{
private:
class Inner;

Inner* inner; // クラスのインスタンスそのものではなくポインタを持つ

public:
Outer(void);
~Outer(void);
};

--- Outer.cpp ---
#include "Outer.h"

class Outer::Inner
{
public:
Inner() {};
~Inner(){};
};

Outer::Outer(void)
: inner(new Inner)
{
}

Outer::~Outer(void)
{
if (inner != 0) delete inner;
}
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!