• ベストアンサー

クラス設計について

C++で通信データのクラス設計をしております。 実際の通信手順ではなく、通信データそのもののクラスの作り方で悩んでおります。 256byteのデータの先頭に識別IDがあり、データを受け取ったらそのID用のデータ表示をするようなことをしたいのですが、どのようにクラスを作ればいいのかが分かりません。 今考えているのは、ベースクラスを作り、そのベースクラスを継承した各ID用の子クラスを作っているのですが、もっといいやり方、いい例などがあれば教えてください。 初めてのクラス設計で悩みまくっています。

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

  • ベストアンサー
  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.2

> 1.DataBaseのコンストラクタでlong id_にデータを代入しているところですが、{0,0,0,1}の並びだと16777216という値で格納されてしまい、create()のswitch文のgetId()id_を取り > 出すと1に該当しなくなってしまいます。 ああ、すんません。パソコン(Intel系のプロセッサ)を使ってるんですね。 Intel系のプロセッサは、バイトの並びが反転するんです。long で 1 ならば、 {0,0,0,1} ではなく {1,0,0,0} としてみてください。 Webサイトを検索するのなら「エンディアン」とか「バイトオーダ」をキーワードに して検索をしてみてください。 > 2.DataTypeA,Bのコンストラクタでid_をのぞいたデータを代入するわけですが、 > たくさんの異なった型が並んでいる場合、ポインタを使わずに簡単に代入できるテクニックなどってありますでしょうか? テクニックというほどではないですが、それぞれの識別ID毎にデータの構造を記述した 構造体を宣言して、それを利用すると、ソースの読みやすさは向上します。 先の回答の DataTypeA のところだけをちょっと書き直してみます。 //------------------------------------------------------------------------ // TYPE 1 // class DataTypeA : public DataBase { public: DataTypeA(char*); ~DataTypeA() {} void print() const; private: short s1_, s2_; struct DataTypeA_info { // このクラスでしか使わないんだから private で十分 short s1; short s2; }; }; DataTypeA::DataTypeA(char* buf) : DataBase(buf) { DataTypeA_info* p = (DataTypeA_info*)getBuf(); s1_ = p->s1; s2_ = p->s2; } どうせ、構造体を記述するのであれば、その構造体をそのままメンバに持つという 選択もありますね。 //------------------------------------------------------------------------ // TYPE 1 // class DataTypeA : public DataBase { public: DataTypeA(char*); ~DataTypeA() {} void print() const; private: struct DataTypeA_info { // このクラスでしか使わないんだから private で十分 short s1; short s2; } info_; }; DataTypeA::DataTypeA(char* buf) : DataBase(buf) { info_ = *(DataTypeA_info*)getBuf(); }

soraprio
質問者

お礼

a-kumaさん、非常にありがとうございました。 自分ひとりでやっていて、なんとかプログラムはかけるものの、果たしてその書き方、考え方が合っているかなんて分からなくて非常に自分に自信がありませんでした。 このように、丁寧に専門家の人に見ていただくと、自分に自信が少し湧きます。 ありがとうございました。

その他の回答 (1)

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.1

> 今考えているのは、ベースクラスを作り、そのベースクラスを継承した各ID用の子クラスを作っているのですが、 基本的には、その方向で良いんじゃないでしょうか。識別IDによる伝文の種類や その扱い方が変わることを考えて。 ちょっと長くなりますが、簡単に書いてみました。あくまでも、実装の仕方の ひとつとして参考にして下さい。ポイントが幾つか。 ・識別IDが伝文のどこにあるかは基底クラスで実装し、派生クラスには隠蔽 ・データ部(識別ID以降)の扱いは、各派生クラスにお任せ ・識別IDによって、どの実装クラスが生成されるかを DataFactory クラスで実装し、利用者には隠蔽 ・識別IDが想定外だと、例外を送出 ひとつのコードに一気に書いてますが、実際には、各クラス毎にヘッダファイルと ソースファイルを作ります。 もし、扱う識別IDが増えた場合には、それを扱う派生クラスのヘッダファイルと ソースファイルを作り、DataFactory の派生クラスを new する行を増やすだけ で済みますね。 あ、ソースは、そのまま Cut & Paste できるように、漢字の空白を使って いませんので、ブラウザでは、ちょっと読み難いですね。 #include <iostream.h> //------------------------------------------------------------------------ // Data Base (にしても、クラス名が良くないね (^^; // class DataBase { public: DataBase() : buf_(NULL) {} DataBase(char* buf) { buf_ = buf; id_ = *(long*)buf_; } virtual ~DataBase() {} virtual void print() const = 0; long getId() const { return id_; } protected: char* getBuf() const { return buf_ + sizeof(long); } private: char* buf_; long id_; }; //------------------------------------------------------------------------ // TYPE 1 // class DataTypeA : public DataBase { public: DataTypeA(char*); ~DataTypeA() {} void print() const; private: short s1_, s2_; }; DataTypeA::DataTypeA(char* buf) : DataBase(buf) { char* p = getBuf(); s1_ = *(short*)p; p += sizeof(short); s2_ = *(short*)p; } void DataTypeA::print() const { cout << "TYPE A : id = " << getId() << ", " << "s = " << s1_ << " " << s2_ << endl; } //------------------------------------------------------------------------ // TYPE 2 // class DataTypeB : public DataBase { public: DataTypeB(char*); ~DataTypeB() {} void print() const; private: long i1_, i2_; }; DataTypeB::DataTypeB(char* buf) : DataBase(buf) { char* p = getBuf(); i1_ = *(long*)p; p += sizeof(long); i2_ = *(long*)p; } void DataTypeB::print() const { cout << "TYPE B : id = " << getId() << ", " << "l = " << i1_ << " " << i2_ << endl; } //------------------------------------------------------------------------ // Factory // class DataFactory { public: DataFactory() {} ~DataFactory() {} DataBase* create(char*) const; long getId(char* buf) const { return *(long*)buf; } }; class BadIdException { public: BadIdException(long id) : id_(id) {} private: long id_; friend ostream& operator<< (ostream&, BadIdException&); }; ostream& operator<< (ostream& o, BadIdException& ex) { o << "ID = " << ex.id_; return o; } DataBase* DataFactory::create(char* buf) const { DataBase* d; switch (getId(buf)) { case 1: d = new DataTypeA(buf); break; case 2: d = new DataTypeB(buf); break; default: throw BadIdException(getId(buf)); } return d; } //------------------------------------------------------------------------ // test code // int main(void) { char buf1[256] = { 0, 0, 0, 1, 0, 2, 0, 3}; char buf2[256] = { 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 19}; char buf3[256] = { 0, 0, 0, 3}; DataFactory factory; DataBase* data; try { data = factory.create(buf1); data->print(); data = factory.create(buf2); data->print(); data = factory.create(buf3); data->print(); } catch (BadIdException& ex) { cout << "Exception ! (bad id). ex : " << ex << endl; } return 0; }

soraprio
質問者

お礼

ありがとうございました。 C++をはじめてまだ4ヶ月なので解読に時間がかかり、丸々一日考えさせてもらいました。 なるほど、このような感じで作ればよいのですね。すごく勉強になりました。 しかも、ものすごく丁寧にありがとうございます。助かりました。 二つほど教えてほしいです。 1.DataBaseのコンストラクタでlong id_にデータを代入しているところですが、{0,0,0,1}の並びだと16777216という値で格納されてしまい、create()のswitch文のgetId()id_を取り出すと1に該当しなくなってしまいます。 {0,0,0,1}のデータの並びでlongに1を代入するにはどうすればよいのでしょうか? あちこちのWebサイトを探してみましたが説明が載っていません。 開発環境はWindows95なのですがなにか関係があるのでしょうか? 2.DataTypeA,Bのコンストラクタでid_をのぞいたデータを代入するわけですが、 たくさんの異なった型が並んでいる場合、ポインタを使わずに簡単に代入できるテクニックなどってありますでしょうか? すいませんがご教授願います。

関連するQ&A

  • クラスの設計の問題

    今C++でクラスの設計をしています。 どう設計すれば、いいか分からないので、しっている方に教えていただきたいですが。 class A{ private: int id; public: int getId(); void setId(); }; class B{ private: int id; public: int getId(); void setId(); } class C{ private: int id; public: int getId(); void setId(); } この三つのクラスが、共通な機能があります。また、実装も同じで、 継承を利用して、どう設計すれば、いいですか? よろしくお願いします。

  • c++でのクラス設計について

     今,c++で色を表すクラスを作っています.  色とはいっても,RGBやXYZなどいろいろな色がありますよね?もし,「各成分の合計を求める」なんて言う関数を作ろうと考えるとすると(必要ないですが^^…)RGBに対しても,XYZに対しても,というように2つ以上作るのは面倒です.そこで,n成分を持つ色のクラスというものを作って,そのクラスを継承して,RGB, XYZなどを表せないかと考えました.  つまり… class color3{ double data[3]; ~~~~~~ }; class rgb : public color3{ ~~~~~~ }; class xyz : public color3{ ~~~~~~ }; (実際color3はtemplateクラスで,double data[3]もポインタを使って要素数を変更できるようにしています.) もちろんこの方法で正常に動いていますが….これではrgbクラスの変数cを宣言して,成分を参照するときに,赤色ならc.data[0],緑色ならc.data[1]というように,data[~]で参照しなければなりません.しかし,これでは見にくいと思っています><.できるなら赤色ならc.r, 緑色ならc.gというように参照したいです.もちろん派生クラスの中にdouble r, g, b; と宣言すればいいのですが… .そうしてしまうと,一番最初の目的が達成できません.ポインタを使ったり,メンバの値を取得する関数(getR(), getX()みたいな…)を作れば解決できますが,この方法を使うと*(c.r), c.r()のような参照をしなければならず,「c.r」というようなきれいな参照はできません.贅沢を言っているようではありますが.c.rと表せるようなクラスの設計の仕方はあるでしょうか?  現在ぼんやりと考えているのは class color3{ double data[3]; ~~~~~~~ }: class rgb : public color3{ double &r = data[0]; double &g = data[1]; double &b = data[2]; ~~~~~~ }; class xyz : public class3{ ~~~~~~ }; のように,参照変数を使えないか,と思っています.もちろん上の方法ではコンパイルエラー となりましたが><  質問が長くなってしまいすいません><  よろしくお願いします. 必要ないかもしれませんが参考までに… 【環  境】MaxOS 10.6 【言  語】c++ 【開発環境】Xcode 【 レベル 】プログラミング歴6年 c歴4年 c++歴1年の大学1年です

  • C++のクラス設計について

    Webや書籍をあたってみたのですが、なかなか解決しないので こちらで相談させいただこうと思い立ちました。 C++で書かれたプログラムを解析しているのですが、 ドキュメントは外部仕様書のみであとはソースコードだけ、という状態です。 コメントもほとんど書かれていないコードについて、リバースエンジニアリングを する必要があり、手始めにクラス図を作成してみました。 すると、複数のクラスでメンバ変数が重複しているのです。 クラスAに、クラスB・C・Dの変数の一部が宣言されていて、 クラスAとクラスBの間で重複している変数はすべてどちらのクラスもprotectedのstatic、 クラスAとクラスC・Dの間で重複している変数はクラスAではprotectedのstatic、 C・Dではprivateです。 クラスBとC・Dは継承関係にありますが、メンバ変数の重複はありません。 クラスAと他クラスは継承関係がなく、メンバ変数が多数重複しています。 クラスAの変数は20個ほどありますが、9割以上がB・C・Dで宣言されている変数と 重複している状態で、かつstaticのprotectedです。 Cはわかるのですが、C++はほとんど書いたことがありません。 アンチパターンなどもあたってみたのですが、上記のような設計についての記述は 見つけられませんでした。こういったクラス間での変数重複は「あり」なのでしょうか? これで情報が足りているかわかりませんが、何卒よろしくお願い致します。

  • クラス設計について

    UMLの本でクラス図の描き方を勉強しています。クラス図を描くためには実際にオブジェクト指向で開発する場合にどのようにクラスを設計するかがわからないのとかけないので、Javaのカテゴリで質問させて頂きます。(未だにクラスをどのように設計するのか、わかっていないので。。) 例えば、以下のような大学の授業登録システムがあったとします。 (1)共通のログイン画面に対して、生徒、先生、アドミニストレータが個々のID・パスワードでログイン出来る。それぞれ出来る操作は異なる。 (2)生徒は、授業の登録、削除が行える。また、自分の登録した授業のスケジュールを印刷することが出来る。 (3)先生は、生徒の評価が行える。自分の持っている授業のスケジュールを印刷出来る。 (4)アドミニストレータは、授業の登録、削除、ログインユーザの登録、削除を行える。 とあった場合、どのようなクラス(属性&操作)を定義しますか?勿論、答えはたくさんあると思いますし、「一般的な答え」というものも存在しないのかも知れませんが、もしご意見が聞けると幸いです。 ※「UMLがわかる」という本ではコントローラとエンティティでクラスを作っているようで参考になったのですが一例しかなかったので上記の場合だとどうなるのかが知りたくて質問致しました。

    • ベストアンサー
    • Java
  • クラスの分割

    画像処理のプログラムを書いているのですが、1つのクラスに必要な変数と関数をぶち込んだため、変数20~、関数20~、2000行くらいのクラスになっています。 このままでは見辛いので、クラスを処理ごとに分割して見易くしたいのですが、各関数でいくつか共通の変数を使用しているため上手く分割ができなくて困っています。 データのみのクラスを継承した子クラスを3つ作ってみたらインスタンスが3つできてしまい意味がありませんでした。 ↓の図に示すようなクラスを作りたいのですが、いくつか質問をさせてください       共通データクラス     /    |    \   子クラスA 子クラスB 子クラスC 1、変数20~、関数20~、2000行くらいのクラスは普通でしょうか?(分割する必要がありますか?) 2、↑の図はクラスの作り方として問題がありますか? 3、2で問題がない場合実現する方法として、仮想継承、関数に共通データのポインタを渡す以外に方法があるかどうか まだまだC++を勉強中で、便利な構造体程度にしか使えていませんが、どなたかご教授お願いします。

  • クラス設計の良い参考書を教えてください

    このたび、仕事で初めてC++を前提にした設計をすることになったのですが、プログラミングも含め、C++自体が全く初めてです(オブジェクト指向自体も初めてです)。あまり時間もないので、良い参考書を探しております。特に、良いクラス設計の思想、設計例などが解説されている参考書などありませんでしょうか。時間が無いので極力邦書を希望します。GoFの再利用のためのデザインパターンの本(業務命令により購入済み)と、平行して進めるつもりですので、これと思想が違わないものが希望です。

  • VB.NET,2005でのオブジェクト指向、クラス設計のポイント。

    VB6ユーザでした。 これから、VisualStudio2005で、VisualBasiの開発を 新規に行う所です。 VB6ユーザの悩み所として、クラス設計があるかと思います。 オブジェクト指向の概念は理解しているのですが、 クラス設計のポイントをアドバイス頂けないでしょうか。 みなさんの、VB.NET、VisualStudio2005等での オブジェクト指向プログラミングの勘所を教えて頂けると 助かります。 思いつく事では・・・ 例1) 顧客DBがあり、いろんな画面から操作する場合、 顧客クラスを用意し、DB操作は、顧客クラスを経由して 行うとか。 例2) 出来るかどうか分かりませんが、 画面で共通部品となる部分を、クラス化し、継承して いくとか。 参考になるHPでも良いので、アドバイスをお願い致します。

  • クラス化ってそもそも何?

    クラスの考え方がいまいち分からなくなりました。 車とか物体で良くサイトとかでクラスについて 書かれてあるけど、逆に分からなくなってきてしまいまして・・; VBで実際のクラスを作成とかになるとどの部分が継承とか っていうのは分かるんですが、クラス自体がこういうものだと 口で言えない自分がいまして・・ こういうものはクラス化したほうが良い一つの例だよ・・的な 事も教えて欲しいです。 まだ明確に分かっていないので・・ 分かる方、ご教授よろしくお願いいたします。 サイトの紹介もありがたいです。

  • 抽象クラスを継承した普通のクラスから、

    抽象クラスを継承した普通のクラスから、 抽象クラス内でprotected宣言したクラスのフィールド(連想配列)へ データをセット&ゲットしてみたいのですが、やり方がよく分かりません。 上記内容を満たす簡単なサンプルを誰か作っていただけないでしょうか。 ちなみに、下記は、自分でやろうとして、頭がこんがらがってしまった例です。 あくまでもイメージですが、 こんな感じで、作成していただけると、うれしいです。 <?php abstract class A1{ protected $data = array();   public function setData($value){ $this->data[$key] = $value; } public function getData($key = null){ if (null == $key) { $this->data; } else { $this->data[$key]; } } } class C1 extends A1{ public function main(){ $this->setData('key1') = 'value1'; $this->setData("キー2") = "値2"; } } $c1 = new C1; $c1 -> main(); var_dump($data); ?>

    • ベストアンサー
    • PHP
  • 僕の持ってるクラスの概念は正しいですか?

    僕の持ってる下記のクラスの概念は正しいですか? クラスとは、データ(「属性」または「フィールド」ともいう)とその操作手順であるメソッド(「振る舞い」、「動作」、「機能」ともいう)をまとめたオブジェクトの雛型(形式・様式を示す見本)を定義したもの。    クラスとは、いわば、何かを実行する物体(オブジェクト)の設計図のようなもの。何かを実行する物体というのは、例えば車をオブジェクトに例えると、「走る」,「車を止める」,「ライトをつける」ということを実行するが、クラスというのはその車(オブジェクト)の設計図。 また設計図だから、クラスの中には具体的に「何をさせたいのか」(車であれば、「走る」,「ライトをつける」等)を記述していくが、これがメソッドである。 また、車であれば、ナンバーや車種等の属性的情報があるが、このようにオブジェクトが保持する属性的情報がフィールドである。 また、この設計図を元に生み出された、実際に動作しているオブジェクトをインスタンスと呼ぶ。 車であれば、実際に走ったり止まったりライトをつけてるといったように、実際に動作しているオブジェクトがインスタンス。 これに関連し、オブジェクトとは、ソフトウェアが扱おうとしている現実世界に存在する物理的あるいは抽象的な実体を、属性(データ、フィールド)とメソッドの集合としてモデル化し、コンピュータ上に再現したもの。

    • ベストアンサー
    • Java