内部クラスのインスタンスを外部クラスが保持する場合

このQ&Aのポイント
  • C++で内部クラスのインスタンスを外部クラスが保持する場合の書き方について説明します。
  • 単純に内部クラスが宣言されている場合は、外部クラスの宣言の後に具体的な定義を書くことができます。
  • しかし、外部クラスが内部クラスのインスタンスを保持している場合は、インスタンス作成より上で外部クラスの宣言内に内部クラスの定義を書かなければなりません。
回答を見る
  • ベストアンサー

内部クラスのインスタンスを外部クラスが保持する場合

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)と思います。具体的な中身がないままインスタンスを 作っているのでエラーを吐く理由もわからないでもないですが、 見易さ的に上の例のようにかけないのかなとも思ったりします。 インスタンスを外部クラスに持たせずともどうとでもなるのですが、 あえて上のようなことをしたくなった場合には下のような方法で記述する以外ないのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • sygh
  • ベストアンサー率76% (42/55)
回答No.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は定義できることになります。

jollno
質問者

お礼

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

その他の回答 (2)

回答No.2

手元にコンパイラがないのでできなかったごめんなさい。 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を多態できるおまけ付きです。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

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

関連するQ&A

  • 内部クラスのスコープについて。

    内部クラスのスコープ、friendクラスのスコープについて詳しいかたお願いします。 以下のクラス構成の場合に、 1.Outerクラスのすべてメンバー関数からはInnerクラスのすべての関数にアクセスできるのでしょうか? 2.InnerクラスからOuter::outerPrivateFunction(); を利用するためにはInnerクラスをOuterクラスのfriendにする方法以外にありますでしょうか? 3.InnerクラスからOuter::outerInt にどのようにしてもアクセスできません。ためした方法はInnerクラスをOuterクラスのfriendにする方法です。 このようなクラス構成にしてしまうと不可能なのでしょうか? 4.friendにしたクラスはprivateの変数、関数にアクセス可能になるはずですが、 それは外部クラスに限ってのことで内部クラスには当てはまらないのでしょうか? class Outer { private: class Inner { Innerfunction(); Onter* pOuter; } outerPrivateFunction(); int outerInt; } 説明に不足があれば補足いたしますのでお詳しいかた宜しくお願いします。

  • 別のクラスのインスタンスの作り方

    現在、javaからrubyに移行するために勉強しているのですが、別のファイルに定義したクラスのインスタンスが作成できなくて、困っています。 具体例をあげると require './B' class A end def initialize b = new B end end --別のファイル class B def initialize p 'hello' end  public : initalize end こんな2つのファイルがあったとして、Aのインスタンスを作成すると、 undefined method `B’ というエラーがでます。 私としてはこのエラーの原因がinitializeがデフォルトでprivate宣言なのが原因だと考えているのですが、publicと指定してもエラーとなることから、いくつか疑問が湧いたので質問させていただきます。 1、そもそもBクラスのインスタンスが作成できないのはinitializeがデフォルトでprivate宣言なのが原因なのか? 2、1があっていたと仮定するとBクラスのinitializeをpublic指定しているのになぜ呼び出せないのか? 3、rubyはなぜデフォルトでinitializeがprivateなのか?(javaではコンストラクタをprivateにするということは普通はしない。使うときはシングルトンやUtilのようなクラスを作るときに限る) 以上です。よろしくお願いします。

    • ベストアンサー
    • Ruby
  • フレンドクラスにできない

    mediatorクラスからCOuterクラスのメンバ変数にアクセスできるようにフレンドクラスにしたつもりなんですが、 うまくアクセスができずコンパイルエラーになってしまいます。 どこが悪いのか分からず困っています。 どなたか助けていただけませんか? mediator.h ----------------------------------------------------- template <class T> class mediator { public: mediator(T* p=NULL) : m_p(p) {} void SetOutClass(T*p) { m_p = pT;} T& GetOutClass() const { return *m_p;} private: T* m_p; }; #define outer GetOutClass() ----------------------------------------------------- COuter.h ----------------------------------------------------- class COuter { private: int m_a; public: void func() { class CInner : public mediator<COuter> { public: CInner(COuter *p) : mediator<COuter>(p) {} void func() { // フレンドクラスなのにアクセスできない!? outer.m_a = 1; } }; CInner inner(this); inner.func(); } friend class mediator<COuter>; }; -----------------------------------------------------

  • 内部クラスから別の内部クラスのインスタンスを取得するには

    早速ではございますが質問をさせていただきます。 以下のクラスで、 ////////////////////////////////////////////////// class A { class B {} class C {} } ////////////////////////////////////////////////// 内部クラスB内で内部クラスCのインスタンスを取得するに はどうすればよいのでしょうか?どうかご教授のほど よろしくお願いします。

    • ベストアンサー
    • Java
  • ローカルインナークラス

    ローカルインナークラスとは、 メソッド内で宣言されるクラス、 ですよね? ある問題に 「メソッドのブロック内でローカルインナークラスを定義した場合正しいものを選びなさい。 ○、インナークラスはfinalで宣言されたローカル変数しか使えない」 ???? ローカルクラスは「外部クラスのメンバ変数への参照更新は可能」ですよね??? 例 class Outer{   int count=0;     void func(){       class Inner{         void display(){           count++;         }       }     } } 外部クラスのcountにアクセスできますよね?? 問題が間違っているのか、 私が考え違いをしているのか、教えてください。

    • ベストアンサー
    • Java
  • C++ のクラスの定義

    C++の初心者です。 C++のことでお聞きしたいことがあります。 namespace test1{ class A { friend class B; protected: int a; }; } とtest1の下にAクラスを作り namespace test2{ class B { public: test1::A A1; }; } と別のnamespaceにBというクラスを作り、 A1というAのインスタンスを持ちたいのです。 しかし、Aというクラスを先に宣言しているので Bというクラスが解らないらしく friendがうまく働きません。 friend class test2::B としても test2がまだ宣言されていないので、 ????とコンパイルエラーが出ます。 先にtest2::B を宣言してしまうと、 今度はtest1::Aが解らずに エラーが出てしまいます。 こんな場合はどのように書けばよろしいのでしょうか? 環境はwindows2000でVC++ 6.0です。 どうか宜しくお願いいたします。

  • 無名内部クラスと匿名内部クラスと匿名クラスの違い

    ■外部クラス ・外部クラスの定義を教えてください ・内部クラスに対して外部クラスと言うのであれば、「クラス内に宣言されたクラスがないクラス(普通のクラス?)」は外部クラスとは言わないのでしょうか? ■無名クラス ・無名クラスは必ず内部クラスなのでしょうか? ■同じ意味? 下記は同じ意味でしょうか? ・無名内部クラス ・匿名クラス ・無名クラス ・匿名内部クラス

    • ベストアンサー
    • Java
  • 基本クラスと派生クラスの宣言順序

    C++のクラスの宣言は、基本クラスから先に宣言しないといけないのでしょうか。 例. 次の順で宣言するとエラーになる。 class A : public B { public: private: } calss B { public: private: }

  • クラスのインスタンス名をクラス内で取得できますか?

    クラスのインスタンス名をクラス内で取得できますか? 今VC++6.0を使っています。例として下記のクラスのコンストラクタで CTest::CTest() { TRACE("%s",typeid(this).name()); } としておいて、 別なクラスで CTest testInst; を生成すると デバッグエリアに 「class CTest *」 と表示することはできました。 これが出来るのなら、インスタンス名 testInst をCTestクラスの内部から 取得することは出来ないのかと思ったのですが、 取得することは可能なのでしょうか?

  • クラスとインスタンスについて

    はじめまして。Javaをはじめて3か月の超初心者です。 早速ではございますが、質問をさせていただきます。 以下のサンプルで、 class Foo { private int i = 0; Foo(int i) { this.i = i; } void func1() { System.out.println(this.i); } void func2(Foo foo) { System.out.println(foo.i); } } class Main { public static void main(String[] args) { Foo obj1 = new Foo(100); Foo obj2 = new Foo(500); obj1.func1(); obj1.func2(obj2); } } privateフィールドのスコープは同一クラス内からしか アクセスできないと参考書には記述されているの ですが、そのクラス内に上のサンプルのように this.iやfoo.iというように、クラスは同じでも インスタンスが異なるものがiにアクセスするとき、 上のサンプルは、どちらもアクセス制限のエラーが表 示されません。なぜなのでしょうか? this.iというアクセスは、現在実行中のインスタン ス内でのアクセスなので、privateスコープ内での アクセスであるというような感じがするのですが、 foo.iというアクセスの方は、現在実行中のインスタンスとは異なるインスタンス内でのアクセスなので、 privateスコープからはずれているような感じがして なりません。

    • ベストアンサー
    • Java

専門家に質問してみよう