• ベストアンサー

基本クラスポインタ = new 派生クラス[i];

基本クラスのポインタ変数pbaseを宣言し、new演算子にて派生クラスの配列を動的に確保して、pbaseに代入した場合、delete[] pbaseは上手く動作するのでしょうか。 (Aのデストラクタは仮想関数にしてあるとしておきます) ------ex-start------ class A {}; class b:public A{}; main() {   A * pbase   pbase = new B[5];   delete[] pbase } ------ex-end------ 例えば、 class Aは12バイト class Bは20バイト である場合、配列のサイズが違うのに、delete[]でちゃんと開放されるのでしょうか。 それともnew/deleteは確保したサイズをシンボル毎に記憶しているのでしょうか。 どうもこの辺が曖昧で実装する時にあやふやになってしまいます。どなたかお知恵をお貸しくださいませ。

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

  • ベストアンサー
  • jmh
  • ベストアンサー率23% (71/304)
回答No.3

struct A { int x; virtual ~A() { cout << "~A: " << this << endl; } }; struct B: A { int y; ~B() { cout << "~B: " << this << endl; } }; B *b = new B[5]; A *a = b; A *a2= a + 2; a2->x = 1; delete[] a; これを素朴に考えると a2 は単純に a に 2 * sizeof(A) バイト足した場所(b[1] と b[2] の中間ぐらい?)を指すかもしれないです。a2->x = 1 は危険な感じがします。 delete [] が、配列の各要素のデストラクタに渡す this を求めるときに同様の失敗をするかもしれないです。 …と今日まで思っていましたが、実際やってみると delete[] で new B[5] が削除できてしまいました(VC++6.0)。不思議です。

tamanegi_majin
質問者

お礼

http://lagendra.s.kanazawa-u.ac.jp/ogurisu/manuals/c/C-faq/C-faq-07.html 7.26に有りました。 メモリが動的に確保された時はそのブロックサイズが記憶されていると予測できます。 と言う事は、ポインタの値が同じならば開放されると言う事っぽいです。その辺は保証されているか不明ですが。 ともかく疑問が消えましたありがとうございます。

tamanegi_majin
質問者

補足

私も、同じような事が出来る事を確認しました。 派生クラスに別のクラスのオブジェクトをメンバとして持たせて、そのデストラクタが呼ばれるかどうかと言うやり方でしたが。 結果は、開放されますね。 初歩的な質問になるのでしょうけれども、free()/deleteで「ポインタ」しか渡しませんよね。 確保されているサイズは渡していないのですが、これってmalloc()/newの時にどこかに記録されてるって事なんですかね。

その他の回答 (2)

回答No.2

シンボル毎というか、オブジェクトごとに大きさを管理していますので、問題なく開放されます。デフォルトのnew/delete演算子は以下の定義です。クラスの区別はなく、大きさのみが渡されます。また、delete演算子はメモリポインタのみです。通常、malloc関数とfree関数で実装されています。 void* operator new [] (size_t sz) { return (void*)malloc(sz); } void operator delete [] (void* pAlloc) { free (pAlloc); }

tamanegi_majin
質問者

補足

ありがとうございます。助かります。 ということは以下の場合も大丈夫なのでしょうか。 ------ex-start------ class A {}; class B:public A{}; main() {   A * pbase;   B * pdri;   pdri = new B[5];   pbase = pdri;   delete[] pbase; } ------ex-end------ 以上の場合と、質問の場合の区別がいまいちつきません。 実行動作はなんとなくわかるのですが。

回答No.1

デストラクターを仮想にしているので問題ないと思います。これはアップキャストの話ですよね。 検索するといろいろ出てきますが適当な一つを紹介しておきます。

参考URL:
http://www1.kcn.ne.jp/~robe/cpphtml/html02/cpp02015.html
tamanegi_majin
質問者

補足

ありがとうございます。助かります。 アップキャストで気になっているのですが、 基底クラスのポインタに、派生クラスのオブジェクトの配列を渡した場合、派生クラスのメンバ変数にアクセスすることは出来ないのでしょうか。 A pbase; pbase = new B[4]; とした場合、Bのメンバ変数にアクセスする場合、もう一度キャストしなおしてやらなくてはいけないのでしょうか。 大本として、これが気になっているのですが。

関連するQ&A

  • クラス内にnewで形成した配列等が含まれる場合

    クラスを関数内に作成した時にそれを実体コピーさせるreturnで返したいんですが、class内newで形成した動的配列があるため、返した後デストラクタが呼ばれるので動的配列の中身が消滅してしまう(させている)のですが、動的配列の消去にデストラクタを使用しないようにするしかありませんか? class a{ public: int *b; a(){b=new int[10];} ~a(){delete b;} //エラー原因 a operator+(a &s){a c;c.b[0] = b[0] + s.b[0];return c;} }; void main() {a x,y;y = x + x;}

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

    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のメンバ関数ではありませんとなってしまいます。 以上よろしくお願いします。

  • クラスのインスタンス作成について

    以下のようなクラス(単純化しています)とテスト関数内でインスタンス生成しています。どちらも意味は同じですが、(1)はtest関数を抜けると勝手に消滅(デストラクタ)してくれますが、(2)はdeleteを使わないと消滅しません。 (2)の方が面倒くさい(new, delete)ですが、(2)を使わないといけない場面や理由が想像できません。クラスの配列なら意味がある???と思いますが、1つのインスタンスで(2)にする場合どんな利点があるのでしょうか? class A { }; void test{ A a; -----> (1) A *pa = new A; -+ (2) delete pa; -+ } あと、A::TEISU = 1とクラスのグローバル定数を設定したいのですがどうすればよいのでしょうか?

  • 基本クラスに派生クラスのインスタンスを持たせたいのですが.....

    A.h//////// #pragma once #include "B.h" class A{ B* b; } B.h/////// #pragma once #include "A.h" class B : public A{ } ////////////// 上のようなクラス構成にさせたいのですが..... #include "A.h"をB.hに追加したところでエラーが出ます。 基本クラスに派生クラスのインスタンスを持たせたいのですが.... どのようにすれば良いでしょうか? エラー内容は : error C2143: 構文エラー : ';' が '*' の前にありません。 : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません この三つが出ます。 何方かよろしくお願いしますm(_ _)m

  • C++ の new演算子について

    C++ の new演算子について質問です。 new演算子を用いてクラスのインスタンスを作ったときに、 クラスのメンバー関数内で使用される自動変数はメモリの何処に割り付けられますか? 以下の回答の内のいずれかと想定しています。 ・ヒープ領域 ・スタック領域 たとえば、以下のように、クラスTestClassが定義されていたとします。 class TestClass { int x; // int型(4byteとする) char y; // char型(1byte) long z; // long型(4byte) void play(short); } void main(void){ TestClass* pt = new a(); play(10); } void TestClass:: play(short n){ char a; long b; static c; for(int a = 0; a < 10; a++ ){ b = n * a; cout << b; } } main関数内で、インスタンスを作成した時点で ・TestClassのデータメンバx,y,z ⇒ ヒープ領域に確保(4+1+4 = 9byte。もしかしたらアライメント     の関係で もう少し大きく領域を確保するかも) ・play関数で使われる変数n,a,bの領域は何処に確保されるのでしょうか? 変数cは静的変数用領域に保存される? new演算子で作ったインスタンスはdelete演算子を使わないと消えないと勉強しました。(OSが消さない限り) つまり、上記ではmain関数を抜けても、変数x,y,z,n,a,bの実体は残ると考えてよいのでしょうか? そう考えると、n,a,bの実体はスタックではなく、ヒープ領域に確保する気がします、、 どうか、ご教授ください。

  • C++でのクラスオブジェクトの破棄

    こんにちは。 C++では、プログラムの終了時に、全てのクラスオブジェクトは、デストラクタが呼び出されて破棄されますが、プログラムの途中で、クラスオブジェクトを明示的に破棄する方法はあるのでしょうか? 例えば、new演算子によってメモリを動的に割り当てたポインタなら、delete演算子で破棄できますが、 クラスオブジェクトにdelete演算子は使えないようです。 何かいい方法を知っておられる方がいらっしゃれば、是非アドバイスを頂きたいと思います。

  • new演算子のオーバーロードについて

    #include <stdio.h> #include <windows.h> class MyNew { public: void* ptr; MyNew( void* p ) { ptr = p; } void* MyNew::operator new( size_t size ) { printf("new-\n"); return malloc( size ); } void MyNew::operator delete( void* ptr ) { printf("delete-\n"); free( ptr ); } }; void main( void ) { MyNew p = new int; } クラスのメモリ確保をnew演算子のオーバーロードを用いて書いてみたのですがオーバーロードしたnew演算子が呼ばれません。 なぜでしょうか? /** VisualStdio2005コンソールアプリケーション WindowsXP */

  • new演算子で困っています。

    基底クラスclass1と派生クラスclass2でnewを使って同じサイズの2次元配列pとqを作ったのですが、メモリ内の同じ場所を参照してるみたいで、class2の配列qで配列の中身を書き換えたら、class1の配列pの中身も書き換えられているんですが、対処法があれば教えてください。 class class1{ protected:      int** p; public:     class1(int n)     {   int i;        *p=new int[n];        for(i=0;i<n;i++){          p[i]=new int[2];        }      }    :    : }; class class2 : public class1{     int** q; public:     class2(int n)     {   int i;        *q=new int[n];        for(i=0;i<n;i++){         q[i]=new int[2];        } }    :    : };

  • new演算子と初期化子 { } の違いについて教えて下さい

    演算子と初期化子 { } の違いがわからなくて調べています。 // newを使った配列 int[] a = new int[3]; a[0] = 1; a[1] = 2; a[2] = 3; // { } を使った配列 int[] a = { 1, 2, 3 }; /* 上記の例は配列ですが、 例えば、配列ではない、Kamokuというクラスを作ったときに、 { } でコンストラクタを使用して、インスタンスを作ることは不可能ですか?メモリは確保しないのでしょうか?

    • ベストアンサー
    • Java
  • 派生クラスの自動生成

    はじめまして。 表題の件に関して質問させていただきます。 Aを親とした派生クラスをn個作るとします。 B1,B2,B3…Bn これらのインスタンスをクラスCのコンストラクタで生成したいとします。 その再Aのポインタを使いたいです。 このような時num_Aという定数をnum_of_A.hh中でnとdefineして #include "num_of_A.hh" class C::C(){ for(int i=0;i<num_A;i++){ A *a[i]=new A(); } } とする以外の方法がないでしょうか? Aを派生させたBを作ると、自動的にその数をカウントしてくれて、Bの数を書いたヘッダファイルなどを用意せずともC中でその数だけ生成してくれる機構を作ることは可能なのでしょうか? 説明がわかりにくくてすみません。 ご存じのかたご教授よろしくお願いいたします。

専門家に質問してみよう