• 締切済み

多数の引数で初期化されるクラスの初期化について。

C++のクラスについての質問なのですが、多数の引数によって初期化され、初期化されないうちは全てのメソッドは機能しないものとします。 このようなclassの初期化についていろいろ考えているのですが、 1,構造体を渡す、  この方法では派生クラスで初期化する場合など凄く難しいと思う。  派生先で動的に決定される場合など、基底クラスより初期化されてくるので、動的に作成した引数を渡せない。 2,初期化専用メソッドをつくり、それが渡されるまで全てのメソッドをブロックする。  初期化されるまでは全てのメソッドは機能しないのだからそのあたりのコーディングが複雑化する。 3,全てコンストラクタの引数に取る。  コンストラクタが非常に長くなる。  デフォルト引数を使えばある程度改善されますが、それでも最後の要素を書き換えたいときなどとても長くなる。 現在は3の方法でコーディングを行っているのですが、このようなクラスの初期化方法でいい方法はないのでしょうか?

みんなの回答

  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.3

#2さんに書かれているように,ファクトリーパタンで実装するのが,一番望ましいでしょうね.

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

# 「初期化済みフラグなどをチェックする」ことを「ブロック」と書かれているように見えますが。 3について。 ・デフォルト処理に頼らず、初期化用factoryクラスを作成する。  (どちらにせよデザインパターン的にも好ましいことが多い) ・このクラスがデフォルトを知っていれば、オプションを予め設定したfactoryを用意しておくことができる。  (コンストラクタのデフォルト引数のような制約はない) もしくは、 > それでも最後の要素を書き換えたいときなどとても長くなる。 ・BoostのNamed Parametersのような名前付き引数を検討する。

参考URL:
http://www.boost.org/
  • clsdi99
  • ベストアンサー率63% (31/49)
回答No.1

やりたい(良い方法を知りたい)のは 1 多くの引数によって初期化したい(良い方法を知りたい) 2 初期化されるまでメソッドを無効化しておく ですよね。 とりあえず2番から。 >2,初期化専用メソッドをつくり、それが渡されるまで全てのメソッドをブロックする。 というのは、初期化の事というより、ブロックの話ですから方法ではないですよね? 一般かどうか分かりませんが、大抵の場合そのクラスが機能するために必要最低限の情報をコンストラクタで渡すのではないでしょうか? つまり、機能できないような宣言(を許すかは別として)されている場合はそれなりの結果でしかメソッドが動かない。と思うのですが。 とは言っても、なにかしらの初期化(コンストラクタ以外、例えばopenなど)をしないと機能しないメソッドもありますね。 この場合やはり、初期化済みフラグなどをチェックするようになると思います。 1番について。 数にもよりますが、多くの引数を渡さなければならない場合はやはり、構造体で渡した方がよいかと思います。 ご心配されている「派生先で動的に決定される場合など」がどのような常態かわかりませんので必ずしも正しいとはいえませんが・・・ たとえばこんな感じですか? class foo {  foo (int,int,int,int,int); << これは面倒  struct init   {    int a;    int b;    int c;    int d;    int e;   };  foo (const init &a); << 構造体で初期化 }; class bar : public foo {  bar ()   : foo (init ?? どうしよう? }; って感じですか? このような場合、派生先のクラスbar のコンストラクタで構造体はもらえませんか?それとも bar 独自の値をいれたいですか? 前者の場合 bar (const init &a)  : foo (a) { } 後者の場合 bar ()  : foo (100, 200, 300, 400, 500) { } こんな感じじゃでめでしょうか?的外れだったらごめんなさい。

関連する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) { } };

  • 派生クラスを含む配列について

    VisualStudio.NETの開発経験があまり無い者です。 WEBサービスを使った開発をするのですが、 対象のメソッドの引数に、特定のクラスの配列を指定するようになっているのですが、 実際にこの引数には、そのクラスの派生クラスのいずれかが入るような感じになっています。 例:ABC(X[]) 引数Xは基底クラスの配列。でもここにはXの派生クラスYやZなどが入る このような場合の実際の指定方法がわかりません。 どのようにしたらよいのでしょうか?

  • 親クラスのコンストラクタは? 引数付きコンストラクタは?

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

  • マネージクラスについて

    マネージクラスで可変長の引数を使いたいのですが、 public ref class CTest { public: CTest(); // コンストラクタ ~CTest(); // デフォルトコンストラクタ !CTest(); // ファイナライザ Msg(PSTR str, ...); // 可変長引数 }; とすると、 「error C3269: マネージ クラスのメンバ関数は '...' と共に宣言することはできません」 というエラーがでてしまいます。 なんとかしてマネージクラスで 可変長の引数を使いたいのですが、方法がわかりません。分かる方いますでしょうか?

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

    コンストラクタの記述について ―引数を持ったクラスを継承する場合― 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
  • テンプレート引数の型推測

    コンパイラはVC++2008です。 いろいろあって、あるクラスにおいて関数ポインタと関数オブジェクト双方を 同じように利用できないかと考えて、次のように試みました。 class Base { public:     virtual void func() =0; }; template<class Func> class CFunc :public Base { private:     Func m_func; public:     CThreadFunc(Func func):m_func(func){}     void func(){m_func();} }; class Hoge { private:     Base* base; public:     template<class Func>     Hoge(Func func)       :base(new CFunc<Func>(func))     {}     ~Hoge()     {       delete base;     }     void DoSomething()     {       base->func();     } }; クラスをテンプレートにするといちいち指定しなければならないので、 まず基底クラスに適当な仮想関数を設け、それを継承したクラスをテンプレートにしました。 そしてコンストラクタの引数で何かしらを受け取って、オーバーライドした関数の中で 関数ポインタか関数オブジェクトだと仮定して呼び出しています。 さらに基底クラスのポインタを目的のクラスが保持してやり、 こちらはコンストラクタをテンプレートにすることで引数から型を推測してもらうことで 先ほどのテンプレートクラスのインスタンスを作成しています。 そしてポインタを介してfunc()を使ったり…、などすれば、 とりあえず引数なしの関数と関数オブジェクトを同等に扱えないかなと思ったからです。 で、このようなクラスを作成してコンパイルすると、 void func(); //何かしら処理する関数 class Function { public:   void operator ()();  //何かしら処理する関数オブジェクト }; があったとして、 int main() {   Function function;   Hoge hoge(function); //いったん作ってから渡す   Hoge hoge2(func); //関数を渡す     hoge.DoSomething();   hoge2.DoSomething();    } は動きました。しかし、 int main() {   Hoge hoge(Function()); //引数を初期化する } とすると次のようなエラーが出ます。 warning C4930: 'Hoge hoge(Function(__cdecl *)(void))': プロトタイプされている関数が呼び出されませんでした (変数の定義が意図されていますか?) また、 int main() {   Hoge hoge(Function()); //引数を初期化する   hoge.DoSomething();  //クラスにアクセス } とすると次のようなほかのエラーが出ます。 error C2228: '.DoSomething' の左側はクラス、構造体、共用体でなければなりません。 しかし、例えば関数オブジェクトのコンストラクタに引数が設定されていたとして、 class Function { public:   Function(int dummy);  //何か値を受け取る   void operator ()();  //何かしら処理する関数オブジェクト }; となっていた時、 int main() {   Hoge hoge(Function(1)); //引数を初期化する   hoge.DoSomething();  //クラスにアクセス } の呼び出しは正常にコンパイルされ、想定通りの動きをします。 全く使わなくても、一つ以上の適当な引数を何でもいいからコンストラクタが持てば、 普通にコンパイルされるみたいです。ただ、デフォルト引数を与えてHoge hoge(Function())と 同じ形ですと引数があってもできないみたいです。 まったく通らないなら最初からあきらめるですが、中途半端にちゃんと動くために エラーの原因を知りたいと思っています。 テンプレートの場合には、引数に渡すタイミングで初期化はしてはいけないのでしょうか?

  • 引数のオブジェクト

    C++のクラスを引数にするとき、そのコンストラクタがオーバーロードされている場合、その引数のところにオーバーロードされているパターンの型を指定できるのでしょうか? また、引数があるクラスで、そのクラスのコンストラクタに更に別のクラスが指定されている場合に、そのクラスのコンストラクタにその指定ができるのでしょうか?

  • クラスがメンバーとしてクラスを持つ時の宣言について

    自作クラスMainClassがMyClassというクラスをメンバー変数として持つ場合、宣言時に引数をいくつか持つコンストラクタを呼び出そうとすると構文エラーとなります。 class MyClass { public: MyClass(int, int); } class MainClass { private: MyClass myclass(10,10); } このような宣言はできないのでしょうか。 引数なしのコンストラクタは呼び出せているようです。

  • JSのクラスについて

    JSのクラスについて https://okwave.jp/qa/q9320085.html の続き >>> >するとCat.nameとなりCatクラスという箱の中に入っているnameプロパティ?いや引数という事なのでしょうか? 引数ではなくプロパティです、ここではクラス内部のローカル変数と説明しているモノです(初心者に分かりやすいか どうかは別としてプロパティと言った方が正確ですね)。 関数内部(関数が持っている)のローカル変数は ご存知ですか?、それに類似しています、この場合はクラス内部(クラスが持っている)のローカル変数と言うイメージです。 Cat.nameとなりCatクラスという箱の中に入っているnameプロパティなのですね。 nameとコンストラクタの引数があるのでthis.nameのnameも引数なのかと思ったのですが、ドットつながりなのでcatクラス(オブジェクト)の中にあるnameプロパティ という事ですね。 関数のスコープの中で宣言する変数のことですよね。 巻き上げが起こる変数ですね。 これとクラス内の変数はほぼ同じ挙動をするという事ですか? するとスコープがクラスにもあるのでしょうか? 巻き上げも >>> >なぜこの例えはこんなわかりにくいことをしたんですかね? 恐らく同じ名前でも「this.」が付いてるか付いてないかで区別できるので、同じ名前でもコンフリクト(衝突、競合)せずに使えると言う例を示したかったのかもしれません。 thisで別の引数?の物と区別できるという事を伝えたかったのですね。 ただ二つはコンストラクタの引数でthis.nameだけはそもそも引数ではなくプロパティなので、 仮にかぶっても問題ないのでしょうね。 >>> >変数と似ている箱で 変数と違う箱と考えて下さい。 オブジェクト、クラス、関数、変数などいろいろな箱がありこんがらがるのですが、 もしかしてこれらはすべて変数なのですか? つまり箱はすべて変数で、これらは少し個性の違う変数なのでしょうか? >>> >特殊な箱でなんでも好きに入れ替えできず、 >入れられるものと入っていなくても良いものが固定されている箱という事でしょうか? >つまり変数と違ってコンストラクタが絶対に入っている箱なのですね。 初期設定が必要ないなら、コンストラクタは必要ないようです。 クラスをインスタンス化したい場合のみコンストラクタは必要で、 インスタンス化が不要なクラスなら必要ないという事でしょうか? ただクラスはインスタンス化しないと利用できないので、 文法上はコンストラクタなしでも良いが、実際はそのようなことはあり得ないという事でよいでしょうか? またインスタンス化と初期設定の違いが判らないのですが、イコールと考えてよいでしょうか? >>> >入れられないものもあるのですか? クラス内クラスは無理なようです。 それ以外はオブジェクトのように入れられるのですね。 >>> >var コンストラクターの「name」= my cat;という事ですかね? その説明は変な感じです、実際のプロセスを考えて下さい(「my cat」ではなく"my cat"文字列です)。 new Cat("my cat") ←ここでコンストラクターの「name」仮引数に"my cat"文字列が代入され、「constructor(name) {this.name = name}」が呼ばれます。 constructor(name) {this.name = name} とは constructor関数の中に中カッコ内の式があり、 catクラス内のnameプロパティにconstructorの引数nameを代入するという事ですよね。 不思議なのはconstructorの引数nameを代入する部分なのですが関数の引数を代入するというのは初めて見ました。 仮引数nameなので constructor(name) { var name = "my cat"; this.name = name } という事ですよね。 つまり下記のcatクラスの引数が実引数になるという事ですよね。 //インスタンス作成 var clsObj = new Cat("my cat"); 関数であれば関数の呼び出しにある引数が実引数として代入されますが、 クラスの場合はconstructor関数の呼び出しにある引数ではなく クラスのインスタンス化にある引数が実引数として代入されるというルールなのですね。 constructor関数の呼び出しがないのが不思議でしたが、 constructor関数は定義するだけで呼び出しはしなくても実行されて、インスタンスを作成するのですね。 そして constructor(name) { var name = "my cat"; this.name = "my cat" } となりプロパティnameに文字列mycatが代入されるのですね。 >>> 「インスタンスの引数」と言うのは違います。 new Cat("my cat"):Catクラスに実引数"my cat"文字列を設定しnewすると、コンストラクターの「name」仮引数に"my cat"文字列が代入され、「constructor(name) {this.name = name}」が呼ばれ、インスタンスが生成されます。 こちらも上記の説明で正しいでしょうか? >>> コンストラクターが在る場合もコンストラクターは初期設定だけです。 クラス"設計図"からインスタンス"実態"を作成すると言う事で、例えるなら十徳ナイフの"設計図"から十徳ナイフの"実態"を作成すると言うイメージして下さい。 (十徳ナイフの"実態"を作成しても)十徳ナイフが置いてあるだけでは何も役に立ちません、十徳ナイフは使ってこそ役に立つ訳です、例えば十徳ナイフの「栓抜き」(機能)を使うと言うのが「栓抜き」メソッド、「缶切」(機能)を使うと言うのが「缶切」メソッドに対応すると言うイメージです。 なるほどクラスがナイフの設計図で、constructor、newクラス名がナイフを作るための作業で、 ナイフがインスタンス化されたオブジェクトですが、この時点では何のメリットもないのですね。 インスタンス化されたオブジェクトを使う作業がメソッドという事ですね。 下記例ですとnew Cat("my cat");がナイフを具現化する作業(constructorもこれに当たる?)で、 実際に使うメソッドはここにはないのですかね? class Cat { (name) {this.name = name} meow() {alert( this.name + 'はミャオと鳴きました' )} } //インスタンス作成 var clsObj = new Cat("my cat"); //インスタンス(オブジェクト)の中身を出力 console.log(clsObj); >>> 仮引数とローカル変数(プロパティー)とは違います。 ローカル変数(プロパティー)はクラスの箱の中に定義されるモノです(添付画像参照)。 上記でも記載した、仮引数と実引数が実質var name = "my cat";というローカル関数と同じ結果になるという意味で書いたのですが、 それでも違うでしょうか? もちろん同じものではないですが、実質同じ結果にはなるのですよね。 >>> そして constructor(name) { var name = "my cat"; this.name = "my cat" } となりプロパティnameに文字列mycatが代入されるのですね。 下記が同じ結果になるという意味なのでしょうね。 >>> 申し訳ございません訂正です、引数を引数としか考えてませんでしたが、ローカルと言われれば確かに引数もローカル変数でした。 関数のローカル変数とインスタンスのプロパティーは類似していますが、インスタンスのプロパティーは値が保持されます。 ちなみに(コンストラクター以外は)クラスの構造がインスタンスの構造に反映されます(添付画像参照)。 関数のローカル変数とインスタンスのプロパティーは類似していますが、インスタンスのプロパティーは値が保持されます。 ここがよくわからないのですがconstructor(name)のnameは引数ではなくプロパティなのですか? 見た目は引数に見えますが、違いとしてはプロパティは値が入れられる箱であり、 仮引数はローカル変数名でしかなく、ローカル変数そのものではないので、箱ではなく、値を入れられないのですかね?

  • 実体化したクラスを関数の引数にするには

    タイトルの通りです。 実体化したクラスを関数の引数として渡し、 関数の中でクラスのメソッドを実行したいと思っています。 以下のソースではエラーが出るのですが、 お分かりの方はいらっしゃいますでしょうか? $o_hoge = new Class_hoge(); fncHoge = ($o_hoge); function fncHoge($class) {  $class->hoge('test'); } class Class_hoge {  public function hoge($a)  {   print $a;  } }

    • ベストアンサー
    • PHP

専門家に質問してみよう