クラス間でのクラスの共有

このQ&Aのポイント
  • クラスAとクラスBの間で情報の共有方法について
  • クラスAとクラスBでの情報共有の最適な方法は何か
  • クラスAがクラスBに情報を渡す方法について
回答を見る
  • ベストアンサー

クラス間でのクラスの共有?

ある処理をするクラスAとログ出力のような動作をするクラスBがあります。 Bクラスはメイン処理及びメインから呼ばれたクラスA両方から呼ばれます。 メイン処理にて、Bクラスのコンストラクタで出力ファイルのパスを指定し その情報をメインから呼ばれたAクラスの中で呼ばれるBでも使用したいと思っています。 クラスを引数として渡せば可能かもしれませんが、できればその方法は使いたくありません。 何か良い方法はありませんでしょうか? void main() { B clsB("c:\\aaa.txt") A clsA; clsA.fnc(); } A::fnc() { clsB.output(); } //Class B.h --------- class B { private: char path[256]; public: B(char *buff); int fnc(); }; //Class B.cpp --------- B::B(char *buff) { strcpy(path, buff); } B::output() { fp = fopen(path, "a"); ・・・ }

  • C_S_C
  • お礼率33% (10/30)

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

  • ベストアンサー
回答No.2

ポインタや参照として、引数として渡すのはスタンダードな方法ですが その場合でも、渡す回数や関数呼び出し回数等は最小限で済むように、カプセル化を十分強めておくことが 大変有効です。 それを踏まえたうえで、別の方法も色々とあります。 方法1. B clsB("c:\\aaa.txt") A clsA; この順番で確実に作るのでしたら、こういうのも考えられます。 class B; //前方宣言 class A { const B* const b; //ポインタ(や参照)を持たせる public: A( const B* b_ ) : b(b_) {} void fnc() const; }; //ソース void A::fnc() const { b->output(); } 方法2. もしAとBが意味的に十分強い関係性を持ち、セットに出来るようなケースでは、方法1のように別々に作ってからポインタを受け渡したりせずに、AがBの生成と破棄を管理してもいいでしょう。 方法3. Bがログ出力専用のようなクラスで、一つだけなど、特定の個数あれば十分な場合 自分自身にstaticな方法でインスタンスを管理させて、どこからでもstatic関数で呼び出せるようにする といった方法も考えられます。 class B { static B* b; //生成されるインスタンス格納用 char path[256]; B( const char* ); //コンストラクタを始め、staticでないメンバはすべてprivateでもOK void output() const; public: static void Init( const char* c ){ b = new B(c); } static void Cleanup(){ delete b; b = NULL; } static void output_S(){ if (b) b->output(); } }; あとはソースに B* B::b( NULL ); とでも書いておきます。 これで、最初の方に B clsB("c:\\aaa.txt") のかわりに B::Init( "c:\\aaa.txt" ); としておき 後は引数として渡さなくてもどこからでも B::output_S(); だけで呼び出せます。 そして終了前に解放します。 B::Cleanup(); 方法4. とりあえず、引数でやるけど クラス数がB,C,D…と増えるといった場合 別に構造体等を作っておいて、それだけいじれば済んでしまう、という形にしてしまうのもいいでしょう。 例 class B; class C; class A { public: void ABC( const B&, const C& ); void ABC2( const B&, const C& ); void ABC3( const B&, const C& ); }; ここにDを単純に加える場合 class B; class C; class D; class A { public: void ABC( const B&, const C&, const D& ); void ABC2( const B&, const C&, const D& ); void ABC3( const B&, const C&, const D& ); }; こうなってしまう、というのであれば stuct DATA { const B* b; const C* c; }; とかを別途作っといて struct DATA; class A { public: void ABC( const DATA& ); void ABC2( const DATA& ); void ABC3( const DATA& ); }; などとしておくことで、このDATA構造体を書き変えるだけで stuct DATA { const B* b; const C* c; }; ↓ stuct DATA { const B* b; const C* c; const D* d; }; 同様の効果が得られます。

その他の回答 (2)

回答No.3

おそらくは、クラスを使うべきではないところで無理やりクラスを使おうとしています。 クラスというのは、たんなる関数の寄せ集めではなくて、ある程度の自律性を持った機能の集合です。 で、一番自然な使い方は、複数のインスタンスを生成して、それぞれのインスタンスごとの振る舞いを行わせるということです。 だから、ログをとるというクラスがあれば、いろいろなログを独立してとる(それぞれに独立したインスタンスが存在する)のであれば、有効です。 一方で、一連のログ(早い話が、ログファイルファイっこしかない)をあちこちで収集するなら、「一連のログをとる」関数郡をひとまとめにすれば言いいのです。 C++には、namespace という機能があって、そういう用途にも使えますから、 logFiles::init(char *filePathName); で最初にログファイルを設定して、 logFiles::appendNormal(char *message); で、正常なログを追記して、 logFiles::appendError(char *message); でエラーログを追記して のようなこともできます。 また、本当に、処理のあちこちで、いろいろなログをとりたいのなら、「このログファイルへの追記」というのがそれぞれ明確でしょうから、「このログファイル」を指定するために、クラスのインスタンスを渡すべきです(というか、インスタンスを渡すのではなくて、「該当するログを担当しているインスタンスに、ログをとるようにメッセージを送信する」という考え方が、正解)

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

普通は「クラス (のインスタンス) を引数として渡す」ものなんだけど.... むしろ, どうして「その方法は使いたくありません」と思ったのでしょうか?

C_S_C
質問者

補足

Tacosanさん回答ありがとうございます。 >どうして「その方法は使いたくありません」と思ったのでしょうか? あくまで予定ではあるのですが 例えばクラスAの複数の関数で呼ぶなどとなった場合や クラスCが追加になった場合など、すべてに引数として渡すのは どうかなと思ったので、ほかの方法があるならそっちの方がいいのかな と考えたからです。 (そもそもコンストラクタなどでファイルパスを指定するのが正しいのか よくわかっていないこともありますが・・・)

関連するQ&A

  • マルチスレッド?

    VC++6.0 コンソールアプリケーションで作成されたプログラムの ある一つのクラスを別スレッドで動かしたいと思っています。 void main () { ~メインの処理~ ClassA clsa; clsa.fnc();←ここを別スレッドで動かしたい ~メインの処理~ } ClassA クラスは閉じたクラスでそこから別のクラスをコールしたりはしません。 なにか参考になるようなサイトなどでもかまいませんので 方法などわかる方は教えてください。

  • スーパークラスのコンストラクタの呼び出し

    こんにちは。 スーパークラスに引数のあるコンストラクタと引数のないコンストラクタをサブクラスで継承する際の質問です。 具体的に書くと下記になります。 class A { A () {} A (int i) {} } class B extends A { } 何がわからないかというと 『スーパークラスのA()は、サブクラスのBでわざわざ明示的にスーパークラスのコンストラクタ呼び出しをしなくても問題ないというのはわかるのですが、なぜスーパークラスのA(int)は、呼び出さなくても良いのかということです。』 もしかしたら基礎中の基礎かもしれませんが、ご教授よろしくお願いいたします。

    • ベストアンサー
    • Java
  • 助けてください。

    C言語の勉強をしているのですがうまくいきません。 助けてください。 氏名、誕生日、血液型を入力し表示する関数を作りたいです。 形としては、氏名を入力し、誕生日を入力したあとに血液型を入力する関数ですが、血液型入力を下の表を表示して選択式にしたいのです。 --------------------------- 番号を入力してください 1;A 2;B 3;O 4;AB 5;? --------------------------- ここで仮に1を入力します。 最終的に入力したものが -------------------- 名前:taro 誕生日:19830917 血液型:A -------------------- と表示されるようにしたいです。 そのための関数を作ったのですが、うまく作動しません。 どこがおかしいか教えてください。 関数はこれです。 #include<stdio.h> #include<string.h> #include<stdlib.h> int main(void) { char Buff[20]; char Buff2[9]; char Buff3[5]; char Buff4[5]; int i; char BLOODNAME[5][4] = {"A","B","O","AB","?"}; printf("名前:"); fgets(Buff,20,stdin); printf("生年月日:"); fgets(Buff2,9,stdin); i = atoi(Buff2); printf("血液型を選べ\n"); printf("------------------------------------\n"); printf("1;A 2;B 3;O 4:AB 5;?\n"); printf("------------------------------------\n"); fgets(Buff3,5,stdin); if(strlen(Buff3) == 1) { switch(Buff3[0]) { case 1: strcpy(Buff4,BLOODNAME[0]); break; case 2: strcpy(Buff4,BLOODNAME[1]); break; case 3: strcpy(Buff4,BLOODNAME[2]); break; case 4: strcpy(Buff4,BLOODNAME[3]); break; case 5: strcpy(Buff4,BLOODNAME[4]); break; default: printf("強制終了ver1\n"); return 0; } } else { printf("強制終了ver2\n"); return 0; } printf("----------------------------------------\n"); printf("名前:%s\n",Buff); printf("生年月日:%d\n",i); printf("血液型:%s\n",Buff4); printf("----------------------------------------\n"); return 0; } あと誕生日なのですが今は入力したものがそのまま出力されますが、最終的には○○○○年○○月○○日と表示されるようにしたいのですが、上の関数にどう追加すればいいのかも教えてください。 お願いいたします・

  • 派生クラスのメンバを基底クラスの参照に代入(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) { } };

  • ソート

    typedef struct{ int num; char name[20]; char type_of_class[8]; double average } data; data seiseki[100]; int main() { data[0].num = 1; strcpy(data[0].name, "山田太郎"); strcpy(data[0].type_of_class, "A_class"); data[0].average = 66.2; data[1].num = 2; strcpy(data[1].name, "鈴木二郎"); strcpy(data[1].type_of_class, "B_class"); data[1].average = 43.1; data[2].num = 3; strcpy(data[2].name, "佐藤三郎"); strcpy(data[2].type_of_class, "A_class"); data[2].average = 39.1; data[3].num = 4; strcpy(data[3].name, "加藤四郎"); strcpy(data[3].type_of_class, "Bclass"); data[3].average = 93.6; data[4].num = 5; strcpy(data[4].name, "石田五郎"); strcpy(data[4].type_of_class, "B_class"); data[4].average = 57.9; data[5].num = 6; strcpy(data[5].name, "草田六郎"); strcpy(data[5].type_of_class, "A_class"); data[5].average = 6.2; //ソート処理 } このように各値が決まってる時 まず同じクラスのものをソートし その中でaverage(平均点)の高い順に並べるソートを行いたいと思います。 最終的には 1,山田一郎,A,66.2 3,佐藤三郎,A,39,1 6,草田六郎,A,6.2 4,加藤四郎,B,93,6 5,石田五郎,B,57.9 2,鈴木二郎,B,43.1 のような感じになってると思います。ソートは行ごとです。 入れ替えの関数はint型のとdouble型のとchar型の3タイプ用意しています。 void intswap(int *p, int *q) { int temp; temp = *p; *p = *q; *q = temp; } void double(double * p, double *q) { double temp; temp = *p; *p = *q; *q = temp; } void wordswap(char p[], charq[]) { char *temp = strdup(p); strcpy(p, q); strcpy(q, temp); free(temp); } 残りがわかりません。 教えて下さい。

  • クラス構造をネストしたの宣言

    クラスA クラスB を使い、お互いに関連した構造にしたいのですが、宣言に困り質問させていただきました。 A.cpp ファイルは class A{ B b; }; のように、クラスB を含んだ状態です。クラスBもクラスAを含んだ状態です。 ここで、オブジェクトファイルを作成すべく、 $g++ -c A.cpp とすると、クラスBが宣言されておらず怒られてしまいます。 クラスBを先に宣言したり、ヘッダーファイルを作成しても、クラスBでもクラスAのオブジェクトを使っているので、やはり"定義されていない"とおこられてしまします。 C言語の関数を入籠にした場合は、プロトタイプを使用して問題を回避しましたが、クラスの場合でこれを解決する手段がわからず質問させていただきました。 どうかご教授ください。

  • 全パッケージの取得、全クラスの取得、全メソッドの取得

    やりたい事は、メインクラスより、同階層の全パッケージを取得(A)、 (A)より同階層の全クラスを取得(B)、 (B)より同階層の全メソッドを取得といったような事です。 例えば public class a { public static void main(String args[]) {  全パッケージの取得  全クラスの取得  全メソッドの取得 } } みたいな感じに。 試行錯誤したのですが、その処理を行う事の出来るメソッドかどうかも良く分からないし、 コンパイルエラーになるばかりで実現が出来ません。  ・メインクラスから同階層のパッケージを取得してパッケージ名を出力。  ・メインクラスからxパッケージ内の同階層のクラスを取得してクラス名を出力。  ・メインクラスからxパッケージにあるyクラス内のメソッドを取得してメソッド名を出力。 上記のようなめちゃくちゃシンプルなコードを挙げてご教示願います。

    • ベストアンサー
    • Java
  • オブジェクト指向における「クラスA have a クラスB」の関係において,クラスBからクラスAのあるメンバ変数だけを触る方法

    クラス10~50個の中規模プログラミングに当たって,以下の問題がよく出てきて, 「簡潔な方法はないものか・・・」と悩んでいます. ●前提条件 【・「クラスAに持たれているクラスB( A have a B 関係)において,   クラスBからクラスAのあるメンバ変数(プロパティ)だけを触りたい」】 この場合,私はよく以下のようにしてしまい,クラス間の独立性を無くしてしまいます. ●方法1: ・クラスBのコンストラクタに「自分の持ち主であるクラスAのオブジェクト」を引数に取り,クラスBの変数(プロパティ)usedClassAとする. ======= C言語風に書くと, <code> public void クラスA{   クラスB usingClassB = new クラスB(); // 持っているクラスB   int commonNum = 0;   public void AddCommonNum(){       commonNum++;    }    ...    (その他の処理)    ... } public void クラスB{    class usedClassA;    // 持ち主のクラスA    // コンストラクタ    public クラスB(クラスA _usedClassA){        usedClassA = _usedClassA;    }    public void AddCommonNum(){        _usedClassA.AddCommonNum();    } } <\code> となります. この方法の問題点は,クラスAとクラスBに<双方向の依存関係を作っている>ことで, クラスAの設計(ここではAddCommonNum())が変更されたときに,クラスBの内容を変更しなければならない可能性があることから,拡張性に欠けると考えています. そこで,他に何かいい実装方法が無いか, 教えていただけないでしょうか? 特に,このような前提条件に汎用的に使える方法だと尚良いです.

  • コレクションクラスでクラスを初期化するには

    環境: VC++.Net2008 C++/CLI Windowsフォームアプリケーション .Net、C++どちらも初めてで勉強しながら作業しています。 VB6.0で開発した経験が1回だけあります。 System.Collections.Generic のListジェネリッククラスを使って、 CSVファイルから読み込んだデータをクラスに格納してフォームから入力された値を比較して同じものがあるかないかの判定を行うプログラムを作成しています。 -------------------------------------- /* データを格納するクラス */ ref class A { char* cphoge; int ihoge; } ref class Amgr { List<A^>^ HOGE; Amgr(); //コンストラクタ {     HOGE = gcnew List<A^>(); /* CSV読み込み処理 */ if(もうCapacityがなかったら) { addで増やす } } } ---------------------------------------- CSV読み込み処理内でHOGE.add(クラス)で容量を増やした後、 読み込んだデータを代入しているのですが、 実行時エラーでSystem.nullreferenceexceptionが起きてしまいます。 調べて要は初期化がちゃんとできていない状態でアクセスしようとしたために実行時エラーで落ちたことはわかったのですが、 肝心の初期化の仕方がわかりません。どなたかご存知の方いましたらご教授よろしくお願い致します。

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

    クラスについて、デフォルトコンストラクタについて理解が乏しいのですが、クラス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; }

専門家に質問してみよう