質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

3914閲覧

C++ 同インスタンス、別クラス

iSnow

総合スコア7

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/12/08 08:21

###前提・実現したいこと
C++で通信プログラムを作成しています。初心者です(汗
通信プロトコルには複数のフレームがあり、そこに記載する内容はさまざまです。
そこで、それぞれのフレームを別々のクラスにし、各クラスでフレームに記載できる内容をメソッドに持たせようと考えました。
例えば、Aフレームで通信するときは、Aフレームの各メソッドに記載内容を渡し(コマンドやサイズなど)最後にgetPacketなどで生成されたデータを取得する。
といった感じです。
そこで、これらのフレームを統合するクラスをつくりたいです。
これの利点は、
・どのフレームを使おうと統合したクラスをincludeまたは継承すれば使える。
・インスタンス化したものに対し使用できるメソッドが限られるため、エラーが減る
だと思っています。
言葉では分かりづらいと思うのでソースコードで理解していただければ幸いです。

私のやりたいことはC++で可能なのでしょうか?

###発生している問題・エラーメッセージ
invalid conversion

###該当のソースコード

C++

1class A{ 2 A(); 3 void method; 4} 5class B{ 6 B(); 7 void method; 8} 9class All{ 10 All(); 11 All* getInstance(type){ 12 switch(type){ 13 case A: 14 A ai = new A(); 15 return ai; 16 case B: 17 B bi = new B(); 18 return bi; 19 } 20 return new All(); 21}

###試したこと
やはり、型が違うと怒られます。
やりたいことは、getInstanceに入力したtypeによってクラスを選択しそのインスタンスを取得することです。こうすれば、各クラスのもつメソッドしか使えないためエラーも減り、使いやすくなると考えています。
よろしくお願いいたします。

###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

やりたいことは、getInstanceに入力したtypeによってクラスを選択しそのインスタンスを取得することです。こうすれば、各クラスのもつメソッドしか使えないためエラーも減り、使いやすくなると考えています。

この考えはよくわかりません。
同じ関数/メソッドから入手したものを、同じように使えないのでは不便ではないですか?

共通するインターフェースを持つ場合

継承を用いることによって、すっきりする可能性があります。

C++

1class Base { 2public: 3 virtual void method(void) = 0; 4 virtual ~Base(void) = default; 5};

しかし、明確なis-a関係でない場合は、むしろ使いづらくなる恐れもあります。

共通するインターフェースが少ない場合

処理自体は簡単なので、テンプレートで実現できます。
しかし、やはり冒頭に書いたように、あまり便利だとは思えません。

投稿2017/12/08 08:59

LouiS0616

総合スコア35658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iSnow

2017/12/08 09:43

ご回答いただきありがとうございます。 だいぶ大雑把な例になってしまいますが、人と鳥というクラスを作ったとします。それぞれは共通の生き物なので、生き物クラスを作ります。 やりたかったことは、 生き物クラスの中で、人か鳥を選択するメソッドを作成し、対応するインスタンスを返すことです。 人クラスのインスタンスを受け取ったら、サイズ、重量、国籍などを設定でき、 鳥クラスのインスタンスを受け取ったら、サイズ、重量、羽の長さなどを設定できるようにします。 こうしたとき、同じ名前のインスタンスで別々のことができると考えたのですが・・・ おっしゃられた通り、あまり便利ではないかもしれませんね。 仮にできたとしても楽になるとすれば、人か鳥を選択した後とくにきにすることなくコーディングできる程度ですし、(includeなど気にせずちらからない)当初考えていたほど便利ではなかったです。 私は、テンプレートの存在は知っていましたが使ったこともない程度の人間なのでまだまだプログラムに対する認識が甘いですね(汗 これからも精進します ありがとうございました。
LouiS0616

2017/12/08 09:53

includeがごちゃごちゃしてしまうのはちょっと問題ありなので、前方宣言について調べてみると良いかもしれませんね。
iSnow

2017/12/08 10:02

ありがとうございます。早速調べてみました! C++にはこんな機能があったのですね。。。勉強になります。 テンプレートも含め理解が追いついていませんが、地道に頑張ります
guest

0

継承とかインタフェースを駆使する事は可能

class Base{ public: virtual vector<byte> getPacket() = 0; } class A : public Base { public: vector<byte> getPacket(); } class B : public Base{ public: vector<byte> getPacket(); void set_hoge(int); } Base* pfactory = new B(); ((B*)pfactory)->set_hoge(0);

投稿2017/12/08 11:06

編集2017/12/08 12:00
asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2017/12/08 12:10

生ポインタで扱うのであれば、Baseクラスに仮想デストラクタを持たせた方が例としていいのではないでしょうか。
iSnow

2017/12/08 15:50

継承、インターフェースは分かりますが・・・vector....orz 勉強して出直してきます ご回答いただきありがとうございます
asm

2017/12/09 00:55

>仮想デストラクタ あぁ、確かにそうでした >vector 生バイト列をポインタとして返すと、長さが分からなくなるので 可変長配列vectorを返す事を思いついた ただ、それだけです
guest

0

ベストアンサー

通信プログラムは組んだことがないので、わかりませんが。

( そのため、用語はわからん。 )

場合( ユーザ入力とか, 使用するプロトコルとか )によって生成するクラスを決定するなら、

デザインパターンのFactoryパターン系 ( Factory, FactoryMethod etc. ) を適用すればいいかと。

単純に考えると、

1. 生成するためのインターフェースクラスを定義する 2. 1を継承&実装したクラスを定義する 3. インターフェース型として生成する

でしょうか。

例えば、IProductインターフェースがあり、それを継承して Product1, Product2クラスを生成する。

UML風に書くと

<< IProduct >> + func1( void ) : bool [ Product1 ] -> IProduct + CONSTRUCTOR + DESUTRUCTOR ... [ Product2 ] -> IProduct 同上

みたいになります。

で、引数によってProduct1, Product2のどれかを生成し、IProduct型として返す関数を定義する。
( クラスでもいいが。 )

C++

1IProduct* CreateInstance( int sw ){ 2 if( sw == 1 ){ 3 return new Product1(); 4 }else{ 5 return new Product2(); 6 } 7}

こうすれば、

IProduct* で引き受けても実体は sw が 1なら Product1, それ以外なら Product2 のになっている。

といっても、まったく関係のないもの ( ファイルの入出力系クラスと メッセージボックスを表示するクラス とか ) だと無理ですが、

ウィンドウ1 と ウィンドウ2 クラスそれぞれ微妙に違うとかなら可能かも。


[追記]

独自のメソッドが呼べないということで(思いつく)解決策を提示しますね。

方法1 : インターフェース側にそのメソッドの概要 ( C言語だとプロトタイプ宣言ってやつ )を記述する メリット: 簡単に作れる デメリット: 実装先も必ず実装する羽目になる
方法2: asmさんが提示されたサンプルコード内のようにキャストで行う メリット: 独自メソッドを使うことができる デメリット: どのクラスから生成したかわからないと厳しい ※ Javaなら instanceof でしたっけ? あれでどのクラスから生成したかわかるようになっているようですが、C++は私が知る限りでは、instanceofにそうとうするのが無いので、別の解決策が必要? ( Qtっていうライブラリ内にはあるようですが、それをするためだけに使うのはアレなので... )
方法3: 独自メソッドは直接いじらずに、そのクラスがやる ( サンプルあり ) メリット: publicだけを見た場合、インターフェースを実装してそれ以外 (独自のメソッド) は存在しないような感じに見える? デメリット: 場合によっては不採用

[方法3を用いた場合]

C++

1class IProduct{ 2 public: 3 virtual bool calc( void ) = 0; 4}; 5 6class CProduct1 : public IProduct{ 7 public: 8 CProduct1(){ /* メンバの初期化等 */ } 9 // デストラクタもあり 10 bool calc(void){ // このメソッド内で独自のメソッドを呼び出す 11 if( privateMethod1() ){ 12 return this->privateMethod(); 13 }else{ 14 return false; 15 } 16 } 17 protected: 18 bool privateMethod1(){ /* 何らかの処理 */ } 19 bool privateMethod2(){ /* 何らかの処理 */ } 20 private: 21 // もちろんメンバ変数も持っている。 22};

( 簡単に言えば間接的呼び出しか。 )

方法4: IProduct, CProduct1, CProduct2 とは別に Product系を管理し間接的に使うようなクラスを定義してソイツで間接的に扱う ( 生成時は 新しく追加したクラスのほうで。 ) メリット: やろうと思えば独自メソッドでも使える デメリット: めんどくさい。クラスが多くなる。場合によっては不採用

[方法4でやった場合]

C++

1class IProduct{ 2 public: 3 virtual bool calc( void ) = 0; 4}; 5 6class CProduct1 : public IProduct{ 7 public: 8 CProduct1(){ /* メンバの初期化等 */ } 9 // デストラクタもあり 10 bool method1(){ /* 何らかの処理 */ } 11 bool method2(){ /* 何らかの処理 */ } 12 bool calc( void ){ /* 何らかの処理 */ } 13 private: 14 // もちろんメンバ変数も持っている。 15}; 16 17class IProductEx{ 18 Public: 19 virtual bool calcEx( void ) = 0; 20 virtual bool clac( void ) = 0; 21}; 22 23class CProductEx : public IProductEx{ 24 public: 25 CProductEx(){ 26 p = new CProduct1(); // 生成 & コンポジション 27 } 28 // デストラクタで p を破棄 29 30 31 bool calc( void ){ 32 return p->calc(); 33 } 34 35 bool calcEx( void ){ 36 if( p->method1() ){ 37 return p->method2(); 38 } 39 return false; 40 } 41 private: 42 CProduct1* p; 43};
方法5: すべてインターフェースに詰め込む メリット: すべて使える デメリット: あるクラスでは使わないメソッドでも実装しないといけない。またクラスの肥大化。

投稿2017/12/08 08:36

編集2017/12/10 02:46
BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iSnow

2017/12/08 09:28

回答していただきありがとうございます! 実際に書いてみたところ、回答していただいた通り別のクラスのインスタンスを取得することができました! ただ・・・プログラマの皆さんには当たり前と言われてしまうのでしょうがProduct1, Product2で別々のメソッドを持っていた場合参照することができませんでした。 確かに、考えてみればコンパイラはどれを選択するかわからないためIProductにないメソッドが呼ばれた場合はエラーを返します。 そこで、IProductに該当のメソッドを仮に追加し、CreateInstanceした後でメソッドを読んだのですが、IProduct内のメソッドが呼ばれてしまいました。 なので、想定どうりには行かず方法を変えるしかないようです・・・ せっかくご回答いただいたのに役立てることができず申し訳ありません。
BeatStar

2017/12/10 02:12

私は趣味でやっているので、詳しくはわかりませんが、 確かに私が提示した方法だと独自のメソッドは呼べません。 (思いつく)解決策を(本体の)解答欄に追記しますね。
iSnow

2017/12/11 01:32

大変詳しく追記していただきありがとうございます! instanceを取得するものは私自身検索してみましたがみつからず・・・やはりなかったのですね むちゃな質問にもかかわらず多くのアイディアを出していただきありがとうございます! ソフトウェアはこの柔軟性が楽しくなりますね。 半ば諦めかけていましたが是非試させてもらいます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問