派生クラスのメンバを基底クラスの参照に代入(C++)

このQ&Aのポイント
  • 派生クラスのメンバを基底クラスの参照に代入することは問題ありませんか。
  • 派生クラスのコンストラクタ内で派生クラスメンバの参照に対して何かしなければ、参照は有効です。
  • 派生クラスのコンストラクタ実行後であれば問題なく動作します。
回答を見る
  • ベストアンサー

派生クラスのメンバを基底クラスの参照に代入(C++

文末のコードのように、 基底クラスで、派生クラスのメンバの参照を持つのはまずいでしょうか。 (classではなくstructにしているのは質問上でのpublic:の省略のためだけです) 初期化順序的には、基底クラスの参照先は、 基底クラスのコンストラクタが走る時点で初期化されていないので、 コンストラクタ内で参照に対して何かしようとすると問題になると思っています。 基底クラスのコンストラクタ内で派生クラスメンバの参照に対して何かしなければ、 参照は有効で、派生クラスのコンストラクタ実行後であれば 問題なく動くと思ってよいでしょうか。 struct A { int& m_ref; A(int& ref) : m_ref(ref) { } }; struct B : public A { int m_obj; B() : A(m_obj) { } };

  • pcook
  • お礼率100% (3/3)

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

  • ベストアンサー
  • teketon
  • ベストアンサー率65% (141/215)
回答No.2

継承は、子が親を知っている状態です。 お話しされているクラスは、親が子を知っている状態で、関係が反転しています。 これは非常に難解な状況で、子の処理結果を親が受け取りたいということなら、 テンプレートメソッドなどで対応するべきです。

pcook
質問者

お礼

ご回答ありがとうございました。 例をint型で書いてしまいましたが、 もう少し正確には、No.3で頂いた回答の補足に 書かせて頂いた内容を目的としていました。 ご提案とはずれるかもしれませんが、 テンプレートクラスで同じようなことが可能で、 こちらの方がご指摘の問題に対して下記の例のように 正しいと感じましたので、書き直しを始めました。 struct Base { }; struct Super1: public Base { }; struct Super2: public Base { }; template <class T> struct A { T m_ref; }; typedef A<Super1> B; typedef A<Super2> C;

その他の回答 (2)

回答No.3

文法上は問題ないけど、それで何をしたいか/何を意図してのことかが気になるところ。 それによってはもっと素直(?)な解決策があるやもしれず。

pcook
質問者

お礼

ありがとうございました。

pcook
質問者

補足

例をint型で書いてしまいましたが、 正確には、派生クラス(B, C)ごとに 用意するクラス(Super1, Super2)が異なるとき、 基底クラス(A)に処理を書きたいので、 その参照を渡したいというものでした。 struct Base { }; struct Super1: public Base { }; struct Super2: public Base { }; struct A { Base& m_ref; A(Base& ref) : m_ref(ref) { } }; struct B : public A { Super1 m_obj; B() : A(m_obj) { } }; struct C: public A { Super2 m_obj; C() : A(m_obj) { } };

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

たぶん動くとは思う. ただ, 「設計をやり直せ」と突き返されても文句は言えないんじゃないかなぁ.

pcook
質問者

お礼

ありがとうございました。やはり違和感ある構成ということですね。

関連するQ&A

  • 仮想基底クラスをもつクラスの代入演算

    仮想基底クラスをもつクラスの代入演算で、仮想基底クラスの代入が各々のサブオブジェクトにつきただ一回なされるようにしたい場合に、みなさん、どのように設計されていますか? 何か、手軽なテクニックがあれば、ご教示ください。 ===(コンストラクタなどは略、アクセス制御も略) たとえば、 struct X { int x; }; struct A : virtual X { int a; }; struct B : virtual X { int b; }; struct C : A, B { int c; }; int main() { C c1, c2; c1 = c2; } として、デフォルト代入に頼ると、c1.x への c2.x の代入を複数回行うコンパイラが多いですよね(というか、きっちり1回のみ行うようにしているコンパイラに出会ったことがない)。C++標準でも、初期化はただ一度とコンパイラが保証するようになっていますが、代入は何度代入してもいいようになっていたと思います。 以下のように、各クラスで、直接の非仮想基底クラスと自身のデータメンバにのみ代入するメンバ関数を定義して、最派生クラスでのみ、仮想基底クラスの代入を行うのが、普通のやり方なんでしょうか。 これでもいいのですが、後に、ある基底クラスに仮想クラスが付け加わったりすると、その基底クラスから派生しているクラスの代入演算の定義をすべていじらないといけなくなるので、もっといいテクニックがあるのなら、と思いまして質問したしだいです。 struct X { int x; X &nvAssign(const X &z) { x = z.x; return *this; } X &operator=(const X &z) { nvAssign(z); } }; struct A : virtual X { int a; A &nvAssign(const A &z) { a = z.a; return *this; } A &operator=(const A &z) { X::nvAssign(z); return nvAssign(z); } }; struct B : virtual X { int b; B &nvAssign(const B &z) { b = z.b; return *this; } B &operator=(const B &z) { X::nvAssign(z); return nvAssign(z); } }; struct C : A, B { int c; C &nvAssign(const C &z) { A::nvAssign(z); B::nvAssign(z); c = z.c; return *this; } C &operator=(const C &z) { X::nvAssign(z); return nvAssign(z); } }; === 1. 仮想基底クラスは何度代入されてもいいようにするもんだ。 2. 仮想基底クラスにデータメンバを持たせるのは間違いだ。 3. 遅くなるから、そもそも仮想基底クラスなど使わない。 という回答は無しでお願いいたします。たぶん、1 か 2 が正解なんでしょうけど^^

  • 仮想基底クラスをもつクラスの代入演算2

    <仮想基底クラスをもつクラスの代入演算>の続きですが、結局、assign のようなものを作って、以下のように書くのが一番いいのでしょうか。。。 ====(一応、自己代入も考慮して書くと^^) #include <algorithm> struct X { int x; X &assign(const X &z, bool top) { if (this != &z) x = z.x; return *this; } X &operator=(const X &z) { return assign(z, true); } }; struct A : virtual X { int a; A &assign(const A &z, bool top) { if (this != &z) { if (top) X::assign(z, false); a = z.a; } return *this; } A &operator=(const A &z) { return assign(z, true); } }; struct B : virtual X { int b; B &assign(const B &z, bool top) { if (this != &z) { if (top) X::assign(z, false); b = z.b; } return *this; } B &operator=(const B &z) { return assign(z, true); } }; struct C : A, B { int c; C &assign(const C &z, bool top) { if (this != &z) { if (top) X::assign(z, false); A::assign(z, false); B::assign(z, false); c = z.c; } return *this; } C &operator=(const C &z) { return assign(z, true); } }; ==== ただ、<仮想基底クラスをもつクラスの代入演算>で、jacta さんが提示してくださった方法も、処理量は増えますが、アロケートする必要があるポインタなどのデータメンバのアロケートやデリートする処理コードをコンストラクタに集中できるので、「コーディング量の減少・改変の際の修正し忘れの可能性を低くできる」というメリットがあると思います。ハンドルクラスやコンテナクラスを実装する際は、swap() 機能が必要となると考えられるので、jacta さんのコピーコンストラクタでコピー代入を実装する方法の方がいいのかとも思います。 みなさん、どう思われますか? また、そのほかに、効果的なテクニックがあれば、ぜひ、ご教示ください。

  • 基本クラスのポインタで、派生クラスのメンバ関数を呼び出す方法?

    VC++でプログラミングをしています。 A(基本クラス) B(派生クラス) を作成しました。Bは、Aの特別な場合です。 このとき、基本クラスAのポインタから、派生クラスBにのみあるメンバ関数を呼ぶことはできないのでしょうか? 基本クラスAにも同じ名前の関数があれば、仮想関数をオーバーロードすれば呼び出せるようですが、この関数は、基本クラスには不要なので、できれば使わないメンバ関数を基本クラスに書きたくありません。 (純粋仮想関数という方法もあるようですが、) 操作としましては、 Aのポインタ配列 A* a[100]を作成し 特別な場合のみ派生クラスBのメンバ関数だけを実行させたいのです。 派生クラスにのみあるメンバ関数を、Readとします。 for(i=0;i<100;i++){ if(派生クラスBの場合){ a[i]->Read() } } 現状では、コンパイルエラーで、 関数Readは、aのメンバ関数ではありませんとなってしまいます。 以上よろしくお願いします。

  • 【C++】相互参照

    以下のような相互参照は、 感覚的には、なるべくならしない方が良いと感じるのですが、 どのようなメリット・デメリットがあるでしょうか? class A B* m_b class B A* m_a ■少なくとも、多くのクラスによって構成された巨大なDLLが、  相互参照ばかりで作られると、  (1)クラスAのポインタ型のメンバーが、クラスB内で値が変わりうる、   また、クラスBを、クラスCで参照していたら、そこでも値が変わりうる。   さらにクラスCを、クラスDで参照していたら、(略)となり、   処理・メンバー値の変更の影響の把握が困難になる。  (2)lib/objの作成順のミスや管理、  (3)いずれかのクラスのリコンパイルが発生した時、   リリース物のリコンパイルが発生しまくる。  ということがあり、良くないと考えています。 - - - - - - - - - - - - - - - 相互にインタフェースし合う項目を、メンバーとして宣言しつつ、 そのGetter、Setterを用意すれば、強結合にせずに作れるという認識ですが合っていますか? class A B* m_b int x1、y1、z1   x1、y1、z1のGetter、Setter class B Privateなメンバーx、y、z int x2、y2、z2   x2、y2、z2のGetter、Setter .

  • 【C#】クラスのコンストラクタ引数参照渡しでエラー

    C#の.NETでWindowsアプリを作成しております。 C++/CLI経験はありますが、C#は全くの素人です。 AクラスからBクラスに、Cクラスを参照渡しで渡し、 BクラスにてCクラスのメンバ変数の値を書き換えた後、 Aクラスでその値を使用するといったプログラムを作成しようと思っています。 Bクラスを生成する際に、コンストラクタの引数渡しにて、 Cクラスを渡す書き方をしたのですが、下記エラー エラー CS0051: アクセシビリティに一貫性がありません。 パラメータの型 'ref Test.C' のアクセシビリティは メソッド 'Test.B.B(ref Test.C)' よりも低く設定されています。 が発生してしまい、解決法が分かりません。 何か根本的なことが間違っているのでしょうか。。 解決策をご存知の方おられましたら、ご教示お願い致します。 下記にサンプルコードを記載します。 【Aクラス】 B b = new B( C c ); 【Bクラス】 namespace Test { public partial class B : Form { public B(ref C c) // コンストラクタ { InitializeComponent(); } } } 【Cクラス】 namespace Test { class C { public int hoge; } }

  • 派生クラスで,基本クラスのメンバ変数である構造体の型を・・・

    派生クラスで,基本クラスのメンバ変数である構造体の型を戻り値の型とするメンバ関数を作りたいのですがエラーが発生してしまいます. class A{ protected: struct NODE{ char *name; NODE *next; } NODE *node; }; class B : public A{ public: NODE* sort(NODE* fnode); }; NODE* B::sort(NODE* fnode){ ←エラー ~~~~~ return ○○; } 現在このような状態です. よろしくお願いします.

  • クラス内で上位クラス内メンバの値を変更

    クラス内で上位クラス内メンバの値を変更 test2Objクラス内で test1Objメンバ内のtest1Valueの値を2に変えたい このような事は可能でしょうか? ================================ class Test2Obj{ public: void changeValue(){ //ここでtest1Objメンバ内のtest1Valueの値を2に変えたい } }; class Test1Obj{ public: int test1Value; Test2Obj *test2Obj; //コンストラクタ Test1Obj(int tmp_test1Value){ setTest1Value(tmp_test1Value); test2Obj=new Test2Obj(); } void setTest1Value(int tmp_test1Value){test1Value=tmp_test1Value;} }; int main(void){ Test1Obj *test1Obj=new Test1Obj(1); printf(">>>%d\n",test1Obj->test1Value); //ここでtest1Obj->test1Valueの値を変えたい test1Obj->test2Obj->changeValue(); } ================================ もしコードに問題があればご指摘をお願いします。

  • 相互参照するクラス、俺こんな日々を暮らすイェー

    C++初心者です。相互参照するクラス(構造体?)の作り方で悩んでいます。一般的な相互参照の解決法は沢山のサイトに載っているのですが・・・ よくある相互参照と解決法 --------------------- struct Test2; struct Test1{ Test2 *t2; }; struct Test2{ Test1 *t1; }; --------------------- これはtest1の中でtest2を使いたい時にその前に名前だけとりあえず宣言しておけばOK(wave)、というもの。(間違ってたらご指摘お願いします。) 自分が現在どうすればいいか途方に暮れている相互参照 --------------------- struct Test2; struct Test1{ int n; Test2 *t2; void Func1(Test2 *t2){ this->t2->m = 777; } }; struct Test2{ int m; Test1 *t1; void Func2(Test1 *t1){ this->t1->n = 777; } }; --------------------- ここでは各メンバ関数内でお互いのメンバを参照します。このときのエラーは、 「Test2のメンバは宣言されていないので、mはTest2のメンバではありません。」 です。これは this->t2->m = 777; の行に対するエラーです。 struct Test2; の行でメンバまで宣言することができません。 どうすれば「Test2の中にmというメンバがあるって後で教えてあげるからちょっとまって」とコンパイラに伝えられるのか、教えてください。お願いします!

  • 基本クラスのポインタから、特定の派生クラスのメンバ変数を変更する方法?

    VC++でプログラミングをしています。 A(基本クラス) A1, A2, A3, ...(派生クラス) を作成しました。A1,A2,A3, ...は、Aの派生クラスです。 このとき、基本クラスAのポインタから、特定の派生クラスにのみ存在するメンバ変数m_dataのみ変更したいのですが、存在するかどうかをどのように判定して、値を変更すれば良いでしょうか? できれば、下記のような構造でループできるとありがたいです。 A* a[100] (その後、a[100]に、派生クラスA1,A2,A3,..を割り当て、  それらが、混在しているとします。) for(i=0 ; i<100 ; i++){ if(a[i]->m_dataが存在する場合){ (2)   a[i]->Set_m_data("m_dataの新しい値") (1)  } } (1)は、a[i]->m_data = "m_dataの新しい値" でも良いです。 現状では、m_dataがメンバでない派生クラスがあるので、 (2)のif文の判定自体ができず困っています。 よろしく御願いします。

  • 親クラスのポインタで派生クラスの関数呼び出し

    下記のようなクラス構成があるとします。 説明のため簡略化しています。 [Test.h] class CParent { protected: int nParent; public: CParent(){nParent = 10;} ~CParent(){}; virtual int func1(){ // (*1) return nParent; } }; class CSub : public CParent { int m_nSub1; // 派生クラスにしかないメンバ変数 int m_nSub2; // 派生クラスにしかないメンバ変数 public: CSub(){m_nSub = 20;} ~CSub(){}; int func1(){ // (*3) return nParent*2; // 20 } // 派生クラスにしかないメンバ関数 int func2() // (*4) { m_nParent; // 10 return m_nSub1; // 不定値 } int SetData(int n) // (*5) { m_nSub2 = n; return m_nSub2; } }; [Test.cpp] void main() { CParent parent; // 親クラスのオブジェクト CParent* pParent = &parent; // 親クラスのオブジェクトを指すポインタ int nRet = 0; nRet = pParent->func1(); // (*1) // サブクラスのポインタ型にキャストする CSub* pSub = (CSub*)pParent; // (*2) nRet = pSub->func1(); // (*3) nRet = pSub->func2(); // (*4) nRet = pSub->SetData(60); // (*5) } (*3)ではpSubの指すオブジェクトが親クラス(CParent)のため、ポリモーフィズムのメカニズムに従ってCParent::func1()が呼ばれ10が返ってきます。ここまでは想定通りです。 次の(*4)ですが、これはCSub::func2()が呼ばれています。なぜこの呼び出しで子クラスの関数を呼ぶことが出来るのでしょうか? 実際その動作をさせたいのですが、なぜそうなるのかが分かりません。想定ではpSubが指す先は親クラスのため、子クラスにしかないメンバ関数func2()は呼べないはずです。 このコードでは、CSubのコンストラクタは通りませんので(そもそもCSub型のインスタンスは実体化していない)、(*4)の呼び出しでは不定値が返ります。また、(*5)は期待通り動作し、戻り値60が返っています。 これは危険な事をしているのでしょうか? 期待通りではあるのですが、なぜこのような動作になるのか理解できません。 上記のようなことをしたい場合、どのように記述するべきでしょうか?

専門家に質問してみよう