アプリ版:「スタンプのみでお礼する」機能のリリースについて

ある処理をするクラス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");
・・・
}

A 回答 (3件)

ポインタや参照として、引数として渡すのはスタンダードな方法ですが


その場合でも、渡す回数や関数呼び出し回数等は最小限で済むように、カプセル化を十分強めておくことが
大変有効です。


それを踏まえたうえで、別の方法も色々とあります。


方法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;
};

同様の効果が得られます。
    • good
    • 0

おそらくは、クラスを使うべきではないところで無理やりクラスを使おうとしています。


クラスというのは、たんなる関数の寄せ集めではなくて、ある程度の自律性を持った機能の集合です。
で、一番自然な使い方は、複数のインスタンスを生成して、それぞれのインスタンスごとの振る舞いを行わせるということです。

だから、ログをとるというクラスがあれば、いろいろなログを独立してとる(それぞれに独立したインスタンスが存在する)のであれば、有効です。
一方で、一連のログ(早い話が、ログファイルファイっこしかない)をあちこちで収集するなら、「一連のログをとる」関数郡をひとまとめにすれば言いいのです。

C++には、namespace という機能があって、そういう用途にも使えますから、

logFiles::init(char *filePathName); で最初にログファイルを設定して、
logFiles::appendNormal(char *message); で、正常なログを追記して、
logFiles::appendError(char *message); でエラーログを追記して

のようなこともできます。

また、本当に、処理のあちこちで、いろいろなログをとりたいのなら、「このログファイルへの追記」というのがそれぞれ明確でしょうから、「このログファイル」を指定するために、クラスのインスタンスを渡すべきです(というか、インスタンスを渡すのではなくて、「該当するログを担当しているインスタンスに、ログをとるようにメッセージを送信する」という考え方が、正解)
    • good
    • 0

普通は「クラス (のインスタンス) を引数として渡す」ものなんだけど....



むしろ, どうして「その方法は使いたくありません」と思ったのでしょうか?

この回答への補足

Tacosanさん回答ありがとうございます。

>どうして「その方法は使いたくありません」と思ったのでしょうか?

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

補足日時:2011/12/19 14:55
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!