ページ 1 / 1
クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 00:38
by array
言語はC++使い、Microsoft Visual C++を使用しています。
コンストラクタに引数を持たせ場合、他のクラスでインスタンス化する際どの様に書けば良いか分かりません。
例)
// 使いたいクラス
class CTest
{
public:
CTest(); // 引数なしのコンストラクタ
CTest( int num1, int num2 ); // 引数のあるコンストラクタ
};
//
class CCall
{
CTest test; // 引数なしでは定義できる
CTest test2( 10, 200 ); // 引数ありだと定義ができない(1)
};
質問の仕方が下手で申し訳ありませんが、意図が分からない部分があれば追記します。
(1)の書き方は構文エラーとなるので、どの様に書けば良いのか困っています。
一応私の分かる範囲だと、(1)は宣言部となるのでCTestを戻り値とした、test2という関数という形でコンパイラに認識されているのかな・・・と思ってます。
(1)の書き方は、実行部で使えば、エラーを出さずインスタンス化できます。
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 00:51
by たかぎ
こんな感じです。
class CCall
{
CTest test2;
public:
CCall() : test2(10, 200) {} // コンストラクタで「メンバ初期化子」を指定する。
};
部分オブジェクトの初期化順序については、タイムリーにもつい何日か前にブログに書いたので、下記を参照してください。
http://www.kijineko.co.jp/node/557
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 00:51
by kaiten
意図があってるか不安ですが……
class CCall
{
CTest test; // 引数なしでは定義できる
public:
CCall() : test( 10 , 200 )
{}
};
といった感じでCCallの初期化子リストで初期化してやればいいのではないでしょうか?
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 01:24
by array
たかぎさん、kaitenさんありがとうございます。
たかぎさんのブログは不定期ですが読ませてもらってます(この場をお借りして少しだけ)。
私はプログラムのマニアックな話を特に興味を持って読ませてもらってます。
前の記事で「 とりあえず memset で初期化 」は印象に残っていたりします。
質問の方は解決しました。
一応結果として、質問の方が不十分だった点も含めて結果を書いておきます。
不十分だった点は、コンストラクタがすでに定義されている場合です。
例)
// 使いたいクラス
class CTest
{
public:
CTest(); // 引数なしのコンストラクタ
CTest( int num1, int num2 ); // 引数のあるコンストラクタ
};
//
class CCall
{
CTest test; // 引数なしでは定義できる
CTest test2( 10, 200 ); // 引数ありだと定義ができない(1)
public:
CCall(); // 他で構文
};
CCall::CCall() : test( 20, 30 ) // 引数ありの方で定義される
{
}
この様な形にすることでコンパイルが通ったので、ちゃんと実行されているかも含めて確認してみます。
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 12:29
by バグ
別のアプローチとして、コンストラクタ内で、newで動的に生成するというのはどうでしょうか?(^_^;)
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 13:06
by array
バグさん貴重なご意見ありがとうございます^^
newで生成する方法は、今回のこの方法で出来なかった場合の最終手段にしようと考えてました。
理由はdeleteを行わなければいけないので、プログラムが途中で強制終了された際、メモリが残ったままになるのか分からなかったからです。
その辺りは例外処理を加えて開放してあげれば問題ないのかもしれませんがあまり分かっていないのでとりあえず、可能な限りnewは使わない方向でプログラミングしています。
ただ、今回の引数ありが何個か存在する場合、見た目が綺麗でないのであまり気に入っていないので最終的にnewを使う方向になるかもしれませんが^^;
例)
// 引数ありの方で複数定義される
CCall::CCall() : test( 20, 30 ), test2(10,30), ...
{
}
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 14:03
by たかぎ
> ただ、今回の引数ありが何個か存在する場合、見た目が綺麗でないのであまり気に入っていないので最終的にnewを使う方向になるかもしれませんが^^;
いや、new を使っても奇麗にはなりませんよ。
CCall::CCall() : test(0), test2(0)
{
try
{
test = new CTest(20, 30);
test2 = new CTest(10, 30);
}
catch (...)
{
delete test;
delete test2;
throw;
}
}
↑のようにするか、std::auto_ptrなどを使うしかないわけで、さらに、デストラクタやコピーコンストラクタや代入演算子も定義しなければならなくなります。
手間は増えますし、どちらかというと汚くなると思いますが...
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 14:49
by array
例外が入ってませんが、個人的には下の形の方が綺麗に見えると思っています。
というのも、今まで関数名の横に、「 CCall::CCall()
: test(0), test2(0), ~ 」というような形を見たことが無かったからなんですが・・・
// 使いたいクラス
class CTest
{
public:
CTest( int num1, int num2 ); // 引数のあるコンストラクタ
};
//
class CCall
{
CTest *test; // ポインタを用意
CTest *test2;
public:
CCall(); // コンストラクタ
~CCall(); // デストラクタ
};
// コンストラクタ
CCall::CCall()
{
test = new CTest(20, 30);
test2 = new CTest(20, 30);
}
// デストラクタ
CCall::~CCall()
{
delete test;
delete test2;
}
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 15:21
by たかぎ
> 例外が入ってませんが、
コンストラクタで複数のオブジェクトを動的に生成する場合は、必ず適切に例外処理を行わなければなりません。
そうでなければ、testの生成に成功した後、test2の生成に失敗して例外が送出されると、testがリークしてしまいます。
Re:クラス内のコンストラクタの引数ありの場合
Posted: 2009年8月02日(日) 15:32
by array
なるほど、やはり動的に確保する場合は細心の注意が必要なんですね。
今後newを使う場合は、No:37610を参考に例外をきちんと入れるようにします^^