🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

6回答

1682閲覧

継承の仕方がわかりません

rosshi

総合スコア5

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2019/11/15 10:19

編集2019/11/17 23:51
public Rs232cController serialController; public class Rs232cController { public byte[] ShortToByte(ushort dum) { byte[] returnData = new byte[2]; returnData[0] = (byte)(dum >> 8); returnData[1] = (byte)(dum); return returnData; } } public class NL9504Controller : Rs232cController { public void WDTSet(int id, byte wdt) { byte[] sendData = new byte[7]; byte[] tmp = new byte[2]; ushort address = 0; address = 0x0E00; tmp = ShortToByte(address); sendData[0] = (byte)'c'; sendData[1] = (byte)0x03; sendData[2] = (byte)id; sendData[3] = (byte)0; sendData[4] = (byte)tmp[0]; sendData[5] = (byte)tmp[1]; sendData[6] = (byte)wdt; Open(); Send(sendData, 7); Close(); sendData[0] = (byte)'c'; sendData[1] = (byte)0x08; sendData[2] = (byte)id; sendData[3] = (byte)0; sendData[4] = (byte)tmp[0]; sendData[5] = (byte)tmp[1]; sendData[6] = (byte)wdt; Open(); Send(sendData, 7); Close(); } } public class TB2448DUTY24 : NL9504Controller { public byte[] CoarseAdjustRead(int id, int bank) { ushort address; byte[] sendData = new byte[6]; byte[] tmp = new byte[2]; byte[] readData1 = new byte[6]; byte[] readData2 = new byte[6]; byte[] returnData = new byte[9]; address = (ushort)(0x0C00 + 0x1000 * (bank)); tmp = ShortToByte(address); sendData[0] = (byte)'c'; sendData[1] = (byte)0x02; sendData[2] = (byte)id; sendData[3] = (byte)5; sendData[4] = tmp[0]; sendData[5] = tmp[1]; Open(); Send(sendData, 6); System.Threading.Thread.Sleep(1); readData1 = Receive(6); Close(); address = (ushort)(0x0C00 + 0x1000 * (bank)); tmp = ShortToByte(address); sendData[0] = (byte)'c'; sendData[1] = (byte)0x07; sendData[2] = (byte)id; sendData[3] = 5; sendData[4] = tmp[0]; sendData[5] = tmp[1]; Open(); Send(sendData, 6); System.Threading.Thread.Sleep(1); readData2 = Receive(6); Close(); returnData[3] = readData1[3]; // Green returnData[4] = readData1[4]; // Green returnData[5] = readData1[5]; // Green returnData[0] = readData2[0]; // Blue returnData[1] = readData2[1]; // Blue returnData[2] = readData2[2]; // Blue returnData[6] = readData2[3]; // Red returnData[7] = readData2[4]; // Red returnData[8] = readData2[5]; // Red return returnData; } }

ウィンドウ起動時に、
serialController = new TB2448DUTY24(communicationData);
を呼び出して、
serialControllerの関数を呼び出そうと思ったのですが、
ShortToByteしか表示されません。
C++では、すべて表示されていたと記憶していたのですが、C#はこんなもんなのですか?
私が何か大きな勘違いをしていますか?
ご教授をお願いいたします。

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

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

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

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

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

y_waiwai

2019/11/15 10:33

このままではコードが読みづらいので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
rosshi

2019/11/17 23:51

ありがとうございます。 <code>ボタンを押しました。
guest

回答6

0

ベストアンサー

ShortToByteしか表示されません。

こちらについては他の回答がついているので細かい説明は割愛します。

ポリモーフィズムを利用したいと考えています。

インターフェース(interface)か仮想メソッド(virtual)を使ってください。

TB2448DUTY24のようなクラス宣言は、実は沢山りまして、最初に場合分けだけして、あとは意識せず使いたいと思ってます。

それ等のクラスに共通の振る舞いがあるならば、インタフェースを使うとポリモーフィズムが行えます。

例えば、HogeクラスがCoarseAdjustReadを持つものだとしたら、TB2448DUTY24 can CoarseAdjustReadかつHoge can CoarseAdjustReadと表現することができます。

文章でcan-doの表現ができるのなら、当然コードでも同じことが表現できるようになります。

C#

1interface ICoarseAdjustReadable { 2 byte[] CoarseAdjustRead (int id, int bank); 3} 4 5public class TB2448DUTY24 : NL9504Controller, ICoarseAdjustReadable { 6 public byte[] CoarseAdjustRead (int id, int bank) { 7 ushort address; 8 byte[] sendData = new byte[6]; 9 byte[] tmp = new byte[2]; 10 byte[] readData1 = new byte[6]; 11 byte[] readData2 = new byte[6]; 12 byte[] returnData = new byte[9]; 13 14 address = (ushort) (0x0C00 + 0x1000 * (bank)); 15 tmp = ShortToByte (address); 16 sendData[0] = (byte) 17 'c'; 18 sendData[1] = (byte) 0x02; 19 sendData[2] = (byte) id; 20 sendData[3] = (byte) 5; 21 sendData[4] = tmp[0]; 22 sendData[5] = tmp[1]; 23 Open (); 24 Send (sendData, 6); 25 System.Threading.Thread.Sleep (1); 26 readData1 = Receive (6); 27 Close (); 28 29 address = (ushort) (0x0C00 + 0x1000 * (bank)); 30 tmp = ShortToByte (address); 31 sendData[0] = (byte) 32 'c'; 33 sendData[1] = (byte) 0x07; 34 sendData[2] = (byte) id; 35 sendData[3] = 5; 36 sendData[4] = tmp[0]; 37 sendData[5] = tmp[1]; 38 Open (); 39 Send (sendData, 6); 40 System.Threading.Thread.Sleep (1); 41 readData2 = Receive (6); 42 Close (); 43 44 returnData[3] = readData1[3]; // Green 45 returnData[4] = readData1[4]; // Green 46 returnData[5] = readData1[5]; // Green 47 48 returnData[0] = readData2[0]; // Blue 49 returnData[1] = readData2[1]; // Blue 50 returnData[2] = readData2[2]; // Blue 51 52 returnData[6] = readData2[3]; // Red 53 returnData[7] = readData2[4]; // Red 54 returnData[8] = readData2[5]; // Red 55 56 return returnData; 57 } 58} 59 60public class Hoge : ICoarseAdjustReadable { 61 public byte[] CoarseAdjustRead (int id, int bank) { 62 return new bytes[1]; 63 } 64}

上記のような実装ができたら、ポリモーフィズムを利用してCoarseAdjustReadを呼び出してください。

C#

1public void Sample(ICoarseAdjustReadable readable){ 2 var bytes = readable.CoarseAdjustRead(1,2); 3 foreach(var b in bytes){ 4 Console.WriteLine(b); 5 } 6}

無理なら抽象クラスか、インターフェース等使うしかないのですね、やはり・・・。関数名が全然同じ機能ではないので、悩んでました。

共通の「振る舞い」が抽出できるのなら、仮に内部の動きに差異があったとしてもインタフェースは利用できると思います。

例えば、時にはCSV形式に、時にはJSON形式にファイルを出力するためのクラスを設計したい。また、それに対してポリモーフィズムを利用して使い分けができるようにしたい。

この場合「CSVに変換する機能」と「JSONに変換する機能」に差異がありますが、「ファイルを出力する」という振る舞い自体は同じです。

なので、インタフェースIFileOutputableを定義することでポリモーフィズムが実現できます。

C#

1interface IFileOutputable{ 2 void Output(string saveFilePath, string fileName); 3} 4 5public class CsvOutput : IFileOutputable{ 6 public void Output(string saveFilePath, string fileName){ 7 //TODO:CSVを出力する処理を実装 8 } 9} 10 11public class JsonOutput : IFileOutputable{ 12 public void Output(string saveFilePath, string fileName){ 13 //TODO:JSONを出力する処理を実装 14 } 15}

※上記は抽象化についての説明に利用しただけです。実際は自作をしない限りCSVはCsvHelperを使って、JSONはJson.NETを使うべきと思います

#最後に
public Rs232cController serialController;の型をTB2448DUTY24にすることでも勿論その場での問題は解決されるかもしれません。
ですが、抽象化ができていないアプリケーションはできているアプリケーションよりも

  • 機能変更の際の修正範囲が大きいため、保守が大変になる
  • 特化(具体化)したクラスしかないため、クラスを別のアプリケーションで再利用しづらい
  • コード量が増えるため、プログラム全体の可読性が悪くなる これはどちらかというと具象化ではなく共通化できていないアプリケーションの話でした

など、あとで技術的な負債が降りかかってくると思います。

なので、もしポリモーフィズムという機能を利用することで、そのアプリケーションの開発が効率的にできる見込みがふんわりとでもあるのなら、継承やインタフェースなどを使った適切なクラス設計ができないか時間をかけてでも検討するべきと思います。

投稿2019/11/18 05:19

編集2019/11/18 07:08
BluOxy

総合スコア2663

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

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

rosshi

2019/11/18 07:18

C++でも仮想関数使ってました。 6年前に書いたコードなので、記憶が間違っていたようです、すいません。 最近、CAD図面しかやってないので、このようなことに・・・(T_T) Classの設計から考えなおしてみます。 みなさんありがとうございました。
guest

0

C#

1Rs232cController serialController;

と宣言している以上、Rs232cControllerのメソッドしか直接は使えません。

C++では、すべて表示されていたと記憶していたのですが

同じ理由でC++でエラー吐きます。


A. serialControllerの型をTB2448DUTY24に変える

B. Rs232cControllerクラスに抽象メソッドを定義して、派生グラスでoverrideする

目的に応じて好きな方をどうぞ

投稿2019/11/18 00:36

ozwk

総合スコア13551

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

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

rosshi

2019/11/18 03:04

回答ありがとうございます。 うちのC++では、普通に動いています、エラーでてないですね・・・。 Aは、代入では駄目でしたので、宣言を変えるという意味ですかね? Bをやりたくないので、こういう形にしたのですが、 無理なら抽象クラスか、インターフェース等使うしかないのですね、やはり・・・。 関数名が全然同じ機能ではないので、悩んでました。
ozwk

2019/11/18 03:22

> 関数名が全然同じ機能ではない 全く違うものに対してポリモーフィズムも何もないと思うんですが
guest

0

C++では、すべて表示されていたと記憶していたのですが、C#はこんなもんなのですか?

私が何か大きな勘違いをしていますか?

質問文だけではちょっと意図がわかりませんでしたが、他の回答のやりとりを見る限り間違いなく大きな勘違いをしてると思います。

親クラスで宣言した変数は、親クラスのメンバ(メソッド等)しか利用できません。
そして、C++/C#等の言語でのポリモーフィズムとは、親クラスで宣言されたシグネチャ(名前・引数)を引き継いで、子クラスがオーバーライドすることで実現するものです。
従って、質問文の例ではポリモーフィズムは何一つ実現できません。

使いたいのは、すべてのメソッドです。

これが「子クラスのみで宣言・実装されたメソッドを含む」という話であれば

ポリモーフィズムを利用したいと考えています。

が無理なのはわかるはずです。

(親クラスではpublic byte[] ShortToByte(ushort dum)のみ宣言・実装されており、子クラスでオーバーライドしていないため)

C++とC#の違い、とかいう以前の問題で、基本的にすべてのオブジェクト指向言語に共通する話です。
このあたりが理解できていないようであれば、今一度、オブジェクト指向基本的な説明をググるなり本を読むなどして復習することをお勧めします。

もし仮にC++で可能だったのにC#で出来ない、という話が本当であれば、C++のソースコードも含めて質問文に提示しましょう。勘違いしている点を指摘してもらえると思います。

投稿2019/11/18 04:52

gentaro

総合スコア8947

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

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

0

メソッド名が異なるものをまとめたところで、ポリモーフィズムとは言い難いです。
単に変数の置き場所を共用しているだけです。

一応、対症療法としては

C#

1if(serialController is TB2448DUTY24 dev) { 2 dev.CoarseAdjustRead(foo, bar); 3}

的な変換ができます。


個人的には、

c#

1bool action(Rs232cController rs232c) { 2 if(rs232c is TB2448DUTY24 dev) { 3 return TB2448DUTY24_action(dev); 4 } 5 else 6 return false; 7}

こんな感じに特定の型のみ受け取る内部メソッド作っておいた方が楽な気がします。

投稿2019/11/18 04:11

編集2019/11/18 04:53
asm

総合スコア15149

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

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

0

Rs232cControllerがShortToByteしかメソッドを持っていないので、ShortToByteしか出ないのは正しいです。

Rs232cControllerはserialControllerの派生にしたかったのではないでしょうか。

もしそうなら、以下のような定義になると思います。

C#

1public class Rs232cController : serialController 2{ 3}

で、しょっぱなの以下のコードはいらないかも。

C#

1public Rs232cController serialController;

投稿2019/11/15 12:05

ta.fu

総合スコア1722

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

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

rosshi

2019/11/17 23:54

使いたいのは、すべてのメソッドです。 しょっぱなのコードは、グローバルに使おうと考えています。 ポリモーフィズムを利用したいと考えています。 オブジェクトによって、動きがことなるような・・・。 TB2448DUTY24のようなクラス宣言は、実は沢山りまして、 最初に場合分けだけして、あとは意識せず使いたいと思ってます。
guest

0

public Rs232cController serialController;

serialController という変数の宣言ですね

ここらへんでなにかエラーが起きそうですが。

投稿2019/11/15 10:38

y_waiwai

総合スコア88038

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問