ここから本文です

c++の例題に分からないところがありました

fun********さん

2012/5/1223:25:54

c++の例題に分からないところがありました

sample code

******

#include <iostream>
using namespace std;

class Ctest {
public:
Ctest() : m_a(0) {
cout << "Default Constructor : m_a = " << m_a << endl;
}

Ctest(int a) : m_a(a) {
cout << "OverLoad Constructor : m_a = " << m_a << endl;
}

int getParam(void) {
return(m_a);
}
private:
int m_a;
};

int main(void)
{
Ctest *p = new Ctest();

Ctest *q = new ((void*)p) Ctest(3);

cout << "pointer p->m_a" << p->getParam() << endl;
cout << "pointer q->m_a" << q->getParam() << endl;
delete p;

return 0;
}


******

一つ目の分からない場所を言います
Ctestのコンストラクターの部分のここです
: m_a(0)
: m_a(a)

もう一つは((void*)p) Ctest(3)
これは分かるようような気がするのですがなぜでしょうか?


ちなみにこのコードはnewを使ってコンストラクタをもう一度呼び出しています
コンストラクターのオーバーロードといったところです。

言葉が不丁寧で申し訳ございません...
回答をお待ちしております。

補足回答どうもありがとうございます。
上の方はしっかりと理解できました
下の方についてはもうすこし聞きたいのです
Ctest *p = new Ctest(); newでインスタンス化
Ctest *q = new ((void*)p) Ctest(3);
この二つについてなのですが
公式は分かっているけれど実際なにが起きているのか分かっていないようです(私)
一体メモリ内では何が起きているのでしょうか?
続けて質問すいません。

閲覧数:
273
回答数:
1

違反報告

ベストアンサーに選ばれた回答

kam********さん

編集あり2012/5/1321:21:05

最初の:m_a(0)と:m_a(a)の部分はメンバイニシャライザという部分で言葉通りにメンバを初期化する部分です。メンバ変数の値を初期化する場合は普通にコンストラクタ内に

m_a = 0;

とか

m_a = a;

という風に書く方法がありますがこれと同じことをメンバイニシャライザを使って行うことができます。以下のように複数の変数を初期化することもできます。

クラス名(): 変数名1(初期値1), 変数名2(初期値2), 変数名3(初期値3) {}

普通の変数を初期化する場合はメンバイニシャライザを使っても使わなくてもどちらでもよいですがconstメンバ変数の場合は必ずメンバイニシャライザを使って初期化しなければなりません。

もう一つの((void*)p) CTest(3)の部分はplacement newや配置newと呼ばれるものです。配置newは普通のnewと違ってメモリを確保しません。
配置newが返すアドレスは指定したアドレスと全く同じなので普通の構造体や変数の場合は単なる型キャストですのでわざわざnewを使って書く必要がありません。
ただしアドレスをクラス型のポインタにキャストする場合、単にキャストしただけではメモリ領域が元のままになってしまうため、主にこのような状況でコンストラクタを呼ぶために使われます。

見ればわかりますが配置newの使い方は以下のようになります。

a = new (void*型アドレス) クラス名([引数], ...);

追記:
例えばすでに確保してある配列などのメモリ領域にオブジェクトを配置したい場合は

char array[256];

CTest *q = new ((void*)array) CTest(3);

というようになります。この場合、qに入っているアドレスと配列arrayの先頭アドレスは全く同じです。CTestのオブジェクトのサイズが4だった場合array[0]からarray[3]まではCTestクラスのメンバ変数が置かれていてそれらはCTestのコンストラクタによって初期化されています。ます。array[0]からarray[3]までを勝手にいじると当然qも同じアドレスを指しているのでq->getParam()の値も変わってきます。

この場合は配置newによってローカル変数のarray[0]からarray[3]までにCTestのオブジェクトを配置しただけですのでdeleteをどこかに書く必要はありません。

通常の配置newはこのように配列などのまとまったメモリ領域のどこかにオブジェクトを配置するときに使われるのでもともと書いてあった普通のnewで確保した領域に配置newを使って新たにオブジェクトを配置するサンプルだけではわかりずらいかもしれません。

質問した人からのコメント

2012/5/13 21:34:28

どうもありがとうございます。
ある程度理解はできました!
もうすこし調べてみようと思いました!
閲覧数60を越えていますね
回答者は一人!
BAさしあげます。

あわせて知りたい

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる