• ベストアンサー

コンストラクタ内でのthisポインタ

 当方、プログラム暦1年の者です。少しわからないことがあるので、ご教授お願いします。  親クラスにstaticなlistを配置し、子クラスがnewされたときに、listに加えていき、好きななタイミングで、自クラスと、継承クラスのインスタンスをすべてdeleteするプログラムを組もうとしています。 コードは /**@brief Base*/ class Base { public: Base(){ List.push_back(this);} virtual ~Base(){//リストから自分を取り除くコード} static std::list<Base*>List; static DeleteAll() {//リスト内のリストをすべてdeleteるる} }; /**@brief Deri1*/ class Deri1 :public Base { public: Deri1(){List.push_back(this);} ~Deri1(){} }; /**@brief Deri2*/ class Deri2 :public Base { public: Deri2(){List.push_back(this);} ~Deri2(){} }; //テストコード int main() { Base*p0 = new Deri1; Base*p1 = new Deri2; //ここですべてのインスタンスが解放される(?) Base::DeleteAll(); return 0; } でここで気がかりが。  継承した際、コンストラクタ内のthisポインタは、変化することもある。という話を聞いたことがあり、もしそれが本当なら、これは上手く動きません。自分でいくつか実験してみましたが、どの結果も、Baseのコンストラクタ内でのthisとDeriNのコンストラクタ内でのthisは同じでした。同じでなくなる状況とは具体的にどのようなときなのでしょうか?また、上の情報はガセネタなのでしょうか?  コンパイラはVS2005standard。です。  

  • qOat
  • お礼率80% (42/52)

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

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

A の導出クラス B のコンストラクタを B::B() { A(); } とすると, 実際には B::B() : A() { A(); } となります. だから, A のコンストラクタを 2回呼び出すことになります (1回は B のオブジェクトのサブオブジェクトとしての A のオブジェクトのため, もう 1回は B のオブジェクトとは無関係な, コンストラクタ本体で使われる無名オブジェクトのため). この場合, 2つのコンストラクタで作られる A の (サブ) オブジェクトは異なるオブジェクトですから, それぞれの this の値は当然異なります>#3. 要するに, 「違うオブジェクトなら this の値は違う」ということを確認しているわけなんですが, 本件とはあんまり関係ないですよね. あるクラスとその基底クラスでコンストラクタにおける this の値が違うのは, やはり多重継承したときでしょう. 例えば #include <cstdio> using namespace std; struct B1 { B1() : x(0) { printf("B1: %p\n", this); } virtual ~B1() { } int x; void printB1() { printf("B1: %p/%p\n", this, &x); } }; struct B2 { B2() : y(0) { printf("B2: %p\n", this); } virtual ~B2() { } int y; void printB2() { printf("B2: %p/%p\n", this, &y); } }; struct D : B1, B2 { D(): z(0) { printf("D: %p\n", this); } ~D() { } int z; void printD() { printf("D: %p/%p\n", this, &z); } }; int main() { D d; ((B1 *)&d)->printB1(); ((B2 *)&d)->printB2(); ((D *)&d)->printD(); } というプログラムで明確だと思います.

qOat
質問者

お礼

大変参考になりました。 確認してみたところ、VC2005環境でも、B1のthisと、Dのthisが同じになりました。 このあと多重継承を含めていろいろやった結果、どれも最初に継承することを示したほうのクラスのthisと継承先のthisが同じになるようです。 返答ありがとうございました。

その他の回答 (3)

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.3

>B::B() における A(); の意味は?>#1 親クラスのコンストラクタを明示的に呼び出さなかった場合に 対する比較のつもりで書きました。(明示的に呼び出したらどうなるか) コード的にはそれほど意味はありませんが、確認した限り、 VC6.0の環境だと、A()呼び出しで表示されるthisポインタの値は 異っていました。

qOat
質問者

お礼

返答ありがとうございます。 aris-wizさんのおっしゃるとおり、vc2005の環境でもそのようになりました。 問題にしている部分は明示的に親のコンストラクタを呼び出さないので、問題はないです。

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

この辺は全て処理系に依存するんだけど, 単一継承する限り Deri1 における this と Base における this は同じにするという処理系が多いんじゃないかなぁ? どう考えてもその方が簡単だし. 言い替えると, 多重継承 (特にダイヤモンド継承) した場合に変化が現れるはずです. ただ, このプログラムは明らかに間違っています. Deri1::Deri1() の中で push_back してはいけません. このままだと, Deri1::Deri1() から勝手に呼び出される Base::Base() の中で push_back して, さらに Deri1::Deri1() でも push_back します. つまり, 「同じオブジェクト」に対して 2回 push_back することになるので, DeleteAll() (おっと, こいつの返り値もないね) で「同じオブジェクトに対して 2回 delete する」はずです. だから, Deri1::Deri1() で push_back してはいけません. ついでにいうと, Base::Base() で push_back すると「間違って new で作らなかったオブジェクト」に対しても delete しちゃいますよね? だから, この形なら Base::operator new(size_t) を定義するべきだと思います. おまけ: B::B() における A(); の意味は?>#1

qOat
質問者

補足

おおっと。タイプミスでした。 Deri1::Deri1(List.push_back(this)); ↓ Deri1::Deri1(); ですね。 >Base::Base() で push_back すると「間違って new で作らなかったオ>ブジェクト」に対しても delete しちゃいますよね? だから, この形>なら Base::operator new(size_t) を定義するべきだと思います. あっ。確かにそうですね。気がつきませんでした。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.1

そもそも、コンストラクタは継承され無かったような。。。 コンストラクタ内で親クラスか同一クラスのコンストラクタを 明示的に呼び出さなかった場合、基本クラスのデフォルト コンストラクタが自動的に呼び出されるだけのはずです。 それ以外に、基本クラスのコンストラクタを明示的に呼び出した場合 基本クラスのコンストラクタのthisが変化したような気がします。 インデントは全角空白なので半角に変換してください //Win XP SP2 / VC++6.0 SP6 #include <iostream> using namespace std; class A { public :  A(){ cout << "A()" << this << endl; };  ~A(){}; }; class B : public A { public :  B(){ A(); };  ~B(){}; }; int main( void ) {  B BBB;  cout << "BBB " << &BBB << endl;  return 0; } こんな感じでしょうか。。。

関連するQ&A

  • コンストラクタについて

    VCの勉強をしています。 ちょっとショッキングなことを聞いてしまいました。 クラスのインスタンスを作成した場合、 コンストラクタは継承もとのコンストラクタもよばれる?? これって本当ですか!! MFCだとクラスの階層はだいぶ深いです。 例えば基本のCviewなんかはCObject>CCmdTarget>CWnd>Cviewの順に継承されています。 MFCでは更にCViewを継承したCTestViewなんてクラスがコードの主役です。 それでCTestViewのインスタンスを作成した場合、 コンストラクタはCTestViewのコンストラクタだけ実行すると思いますが、 ショッキングな内容ではCViewのコンストラクタも実行されてます。 これって本当にそうなるのでしょうか。 もし、そうならコンストラクタはてっぺんのCObjectから順に実行されますか。 それとも1つ上の継承先だけですか。 また、何でこんな仕組みにする必要があるのですか? 更にいえばCObjectにはSerializeという関数があります。 これをCTestView.serializeとした場合、 CObjectから順々にSerializeが呼び出されているのでしょうか? そんなことあるわけないよと、あまりにもバカバカしいのですが、 知人がそうだと言い張るのでよろしくお願いします。

  • Javaコンストラクタthisとsuperについて

    javaのthisとsuperの理解の為に下記のようなクラスで実験してみているのですが、 少し解らない箇所が出てきました。 コメントアウト行(1)に書いたようにsuper()を書くとエラーが発生してしまいます。 確かsuper()はコンパイラが自動的にコンストラクタが実行された時1行目に挿入している。 と覚えていたので明示的にしようとしたのですが、どうやら認識違いのようでして、だとしたら Q1:super()はいつ呼ばれているのでしょうか? また、ConstThisTestは暗黙的にObjectクラスを継承しているはずなので Q2:Objectクラスのコンストラクタが呼ばれているはずですが、 いつ呼ばれているかをログなどで確認する方法はありますでしょうか? 因みに開発環境はeclipseを使用しております。 尚javaのバージョンやeclipseのバージョン等は 今回は関係ないかなと思うので記載しておりません。 以上 何卒宜しくお願い致します。 --------------------------------------------------------- public class ConstThisTest { int constValue = 0 ; public ConstThisTest(int constValue) { this.constValue = constValue; } public ConstThisTest() {        /* (1)super()を書くとthis()は1行目にかかないと          コンストラクタ内の最初のステートメントであることが必要とエラーが出る。 */ this(-1); } public void printValue(){ System.out.println("constValue = " + constValue); } } public class ConstThisTestMain { public static void main(String[] args) { ConstThisTest ct = new ConstThisTest(); ct.printValue(); } }

    • ベストアンサー
    • Java
  • 親クラスのコンストラクタは? 引数付きコンストラクタは?

    VisualBasic.NETです。 あるクラスを継承したクラスからインスタンスを作成したときに、派生クラスのコンストラクタは呼び出されると思うのですが、基本クラスのコンストラクタはどうなるのでしょうか? JAVAのように、super() で呼び出す必要があるのでしょうか? 自動で呼び出されるのでしょうか? それとも、そもそも呼び出せないのでしょうか? また、引数の個数が違うコンストラクタは、同じクラス内に設定できるのでしょうか? JAVAのコードを移植しようと考えているのですが、出来るのかどうかが分からずに悩んでいます。 ご存じの方、よろしくお願いします。

  • STLでポインタのリストをsort()する方法を教えてください

    STLのsort()の使い方が分からず困っています。 定義したクラスから生成したオブジェクト群を list で管理しています。 ↓こんな形です。 class cMyClass { int m_Attr; public: cMyClass(); ~cMyClass(); }; std :: list <cMyClass*> m_MyList; m_MyList.push_back(new cMyClass); m_MyList.push_back(new cMyClass); ... この、m_MyListを cMyClass内の要素 m_Attr の大小でソートしたいのですが、どうにもやり方が分りません。。。 教えていただけないでしょうか。 よろしくお願いします。

  • デフォルトコンストラクタについて

    クラスについて、デフォルトコンストラクタについて理解が乏しいのですが、クラスB側で何か細工をすると、クラスAのデフォルトコンストラクタ無しで、エラーなくコンパイルできるのでしょうか? 派生クラスの親のベースクラスのコンストラクタを呼ぶsuper?でOKなのでしょうか? #include "stdafx.h" class A { public: //A(){} // これをコメントアウトにすると // error C2512: 'B' : クラス、構造体、共用体にデフォルト コンストラクタがありません。 A(int x){} ~A(){}; }; class B : A { }; void main(void){ B b; }

  • コンストラクタの動作について

    下記のソースについて質問があります。 public class Test{ private String msg; public Test(){ this("Good morning"); } public Test(String msg){ msg = msg; } public String toString(){ /*(2)*/ return ("msg:" + msg); } public static void main(String args[]){ System.out.println(new Test()); /*(1)*/ } } このコードをコンパイルした出力結果は、 msg:null となるのですが、ここの仕組みがわかりません。 (1)でTestクラスのコンストラクタを呼び出し、msgに"Good morning"を設定し、 処理が終わると思うのですが、(2)の処理も行われてしまいます。 (1)では、Testのコンストラクタを設定しているだけに見えてしまうのですが、 (2)まで処理が行われるのは、何故かのかをご教授の程お願い致します。

    • ベストアンサー
    • Java
  • (クラス名.this.メソッド)って・・・?

    次のようなクラスで public class ClassA {   public static void main(String[]args)   {     new ClassA(); /* 構築A */   }   public ClassA()   {     new ClassI();   }   public class ClassI()   {     ClassA.this.MethodA(); /* 命令A */   }   public void MethodA()   {     System.out.println("HELLO");   } } この命令Aの部分の (クラス名.this.メソッド)というアクセス方法がよくわかりません とりあえす(ClassA.this)が構築Aの部分で生成された インスタンスではないかとおもうのですがそれで正しいのでしょうか? また インナークラスはインナークラスの定義されているクラス以外から インスタンスを生成できないのでしょうか? つまり次のクラスを追加して public class ClassB {   public ClassB()   {     new ClassA.ClassI(); /* 構築B */   } } ここの構築Bのように(この場合はダメの様ですが)他のクラスから 構築することです もし仮にできるとしたら そのときの命令Aの(ClassA.this)は一体なんの インスタンスを指すのでしょうか 急ぎのプログラムを作っているので たいへん不躾ですが、なるべく早くお答えをお願いします

    • ベストアンサー
    • Java
  • クラスや構造体のarrayを作りたい。

    クラスや構造体のarrayを作りたい。 クラスや構造体のarrayを作りたいのですが、 以下の方法で正しいのでしょうか? ==================================== #include <string> #include <vector> class Test{ public:   std::string sono1;   int sono2;   bool sono3;   //コンストラクタ   Test(std::string tmp_sono1,int tmp_sono2,bool tmp_sono3){     sono1=tmp_sono1;     sono2=tmp_sono2;     sono3=tmp_sono3;   } }; void main(){   std::vector<Test> testObjArray;   testObjArray.push_back(*(new Test("てすと1",1,true)));   testObjArray.push_back(*(new Test("てすと2",2,false))); } ==================================== 質問1: コンストラクタ時、クラス内の変数へ引数の値を渡す時、 上記のようにtmpを作成する以外の方法はありますか? 質問2: push_back時、クラスをインスタンスしてvectorに渡すにはこのような記述であってるのでしょうか? 「testObjArray.push_back(*(new Test("てすと1",1,true)));」 一応問題なく動いているようなのですが心配です。 よろしくお願いします。

  • コンストラクタの記述について ―引数を持ったクラスを継承する場合―

    コンストラクタの記述について ―引数を持ったクラスを継承する場合― ActionScript3.0でプログラミングをしています。 クラスの継承に挑戦したのですが、うまくいきません。 コンストラクタの記述は、何か特別なものが必要なのでしょうか? ■コンストラクタに引数なし → 成功。 ■コンストラクタに引数あり → 失敗。  エラー「No default constructor found in base class <親クラスの名前>」。 ■エラーの出るソース↓ ・Main.as(コンストラクタ内抜粋)     var parent:Parent = new Parent(100);     var child:Child = new Child(200); ・Parent.as package {   import flash.display.Sprite;      public class Parent extends Sprite {     protected var str:String = "親クラスのプロパティ";     public function Parent(inNum:Number):void {       trace("親クラス, ", str, inNum);     }   } } ・Child.as package {   import Parent;   public class Child extends Parent {     public function Child(inNum:Number):void { //■エラー。       trace("子クラス, ", str, inNum);     }   } } ご存知の方、よろしくお願いします。 よろしくお願いします!

    • ベストアンサー
    • Flash
  • 【PHP】コンストラクタ―について

    コンストラクタ―について検索して調べると概ね以下のように説明されています。 ---------------------------------- コンストラクタ インスタンス生成時にオブジェクトを初期化したい場合にコンストラクタメソッドを使用できます。 コンストラクタメソッドは以下のように引数を指定する事もでき、インスタンス生成時に__construct()が自動的に実行されます。 ---------------------------------- イマイチ判然としません。 「newによってインスタンスを作成される時に自動的に呼び出されるもの」と自分では解釈していました。 例えば以下のような場合 public function __construct($text) { $this->text = $text; } 【$text】の値をnewされることによって自動的に「保持」されるということなのでしょうか? 実際に表示させるときは【$posts[0]->show();】(show()メソッド)で表示させるわけですよね? その上には【private $text;】でプロパティがあります。 ごく基本的な質問かと思いますが、【public function __construct($text)】 コンストラクタ―を作成する理由がよくわかりません。 初学者でも分かりやすいように解説していただけないでしょうか? 宜しくお願い致します。 <記述サンプル> ------------------------------- <?php class Post { private $text; public function __construct($text) { $this->text = $text; } public function show() { printf('%s' . PHP_EOL, $this->text); } } class SponsoredPost extends Post { private $sponsor; public function __construct($text, $sponsor) { parent::__construct($text); $this->sponsor = $sponsor; } public function showSponsor() { printf('%s', $this->sponsor); } } $posts = []; $posts[0] = new Post('hello'); $posts[1] = new Post('hello again'); $posts[2] = new SponsoredPost('hello hello', 'Yahoo'); $posts[0]->show(); $posts[1]->show(); $posts[2]->show(); $posts[2]->showSponsor();

    • ベストアンサー
    • PHP

専門家に質問してみよう