- ベストアンサー
ポリモーフィズムの実現方法とは?
- VBのOption Strict Onを使って、ポリモーフィズムを実現する方法を教えてください。
- Option Strict Onを設定することで、コンパイルエラーを抑止することができます。
- ポリモーフィズムを効かすためには継承階層を上位の方向に対して通常にキャストなしで代入できるようにする必要があります。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
お世話になります。 どうも、仕様のようです。 http://msdn2.microsoft.com/ja-jp/library/d26b27bt(d=ide).aspx > じゃ、ByRefっていったいどんな時に使うものなんでしょう? > > 1)プリミティブについてのByVal > 2)プリミティブについてのByRef > 3)値型についてのByVal > 4)値型についてのByRef > 5)参照型についてのByVal > 6)参照型についてのByRef > (3)と(4)も基本的にそれと、同じイメージで > 考えていいのでしょうか? 1) 2) が Integer 等を示していて、 3) 4) が 構造体 等の事を示されているのであれば、 そうだと思います。 私個人の経験ですが、 ByRef が必要な時ってあんまりないです。 関数を作る場合は、Return で値を返却するように 設計するのが標準的だと思っております。 ちなみに、値型以外のものを引数で渡す場合は ポインタ渡しになります。 それで、 Dim frmTestForm As TestForm Utils.CreateForm("TestForm", frmTestForm) こちらの 2 行目を実行する際の frmTestForm は 値もポインタも Null です。 なので、NullReference Exception が発生しているものと思われます。
その他の回答 (1)
- naganaga_001
- ベストアンサー率71% (172/242)
お世話になります。 > 引数として、Base型をとるメソッドにその派生型の > オブジェクトを引き渡すような呼び出しの > ところで、怒られてしまいました? いや、 下の例で言うと、AnimalCry メソッドへ myCat を渡しているところが該当箇所だと思いますが これは怒られないです。 Option Strict On Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim myDog As Animal = New Dog("taro") Dim myCat As Cat = New Cat("hanako") Me.AnimalCry(myDog) Me.AnimalCry(myCat) End Sub Public Sub AnimalCry(ByVal ani As Animal) Console.WriteLine(ani.Name) ani.Cry() End Sub End Class ' 抽象動物クラス Public MustInherit Class Animal Protected m_name As String Public ReadOnly Property Name() As String Get Return Me.m_name End Get End Property Public Sub New(ByVal name As String) Me.m_name = name End Sub Public MustOverride Sub Cry() End Class ' 犬クラス Public Class Dog : Inherits Animal Public Sub New(ByVal name As String) MyBase.New(name) End Sub Public Overrides Sub Cry() Console.WriteLine("wan") End Sub End Class ' 猫クラス Public Class Cat : Inherits Animal Public Sub New(ByVal name As String) MyBase.New(name) End Sub Public Overrides Sub Cry() Console.WriteLine("nya") End Sub End Class
お礼
さっそくありがとうございます。 ↑ですが、うまく動いてるようです。 ただ、 Public Sub AnimalCry(ByVal ani As Animal) を Public Sub AnimalCry(ByRef ani As Animal) とByRefに変更すると、 「Option Strict On で'Animal'から'Cat'への暗黙的な変換はできません。」と怒られてしまいます どうやら、引数を与える時というより、 "メソッドの実装の中で実引数が更新される可能性があるシグニチャであるが、その際は、呼び出し元では、 Cat型ということになっているものにAnimalをキャストなしで、代入することになりますが、それは、Option Strict Onにひっかかるんじゃないですか?という意味内容の警告に見えます。 Animal自体がVB.NETでいうところの参照型なので、 ByValにしても、Animal* 型のイメージになるという ことでしょうか? だとすると、ByRefだと、Animal**のイメージなんですか? じゃ、ByRefっていったいどんな時に使うものなんでしょう? 1)プリミティブについてのByVal 2)プリミティブについてのByRef 3)値型についてのByVal 4)値型についてのByRef 5)参照型についてのByVal 6)参照型についてのByRef (1)と(2)の違いは、(2)では、いわゆるSwap関数を 実現するような時に違いがでるイメージに見えます。 (3)と(4)も基本的にそれと、同じイメージで 考えていいのでしょうか? そして、(5)と(6)が、今回問題になってる違いですね?これは、いかに?? よろしくお願いします。
補足
例えば以下のようなコードがあります。 Option Strict Offで実行すると、 新たにTestFormをモーダルで起動してくれます。 CreateFormの中で、frmTestFormに実態を代入してくれることを期待しています。 戻ってきたら、 frmTestForm.ShowDialog() でモーダル起動しています。 しかし、Option Strict Onにすると、コンパイラに おこられてしまうので、 しぶしぶ、 Public Shared Sub CreateForm(ByVal ts As String, ByRef f As Form) を Public Shared Sub CreateForm(ByVal ts As String, ByVal f As Form) と ByVal f As Form に変更して、実行しました。 すると、 frmTestForm.ShowDialog() にて、NullReference Exception で怒られてしまいます。 実は事情があって、古いDelphiのコードをVB.NETに コンバートしなければ、ならない部分があり、 その旧Delphiコードがメソッド内部で、値を代入する イメージのロジックが結構あったんです。 リスクを回避するため、できるだけ、旧コードを流用したいので、そのままのイメージで変換したい。 しかし、Option Strict Onにひっかかってしまう!! ・質問文および、お礼で、質問している辺りの 知識が深く関係していると思うので、その辺りを 確認したかったのが、今回の質問の趣旨です。 Public Class TestForm Inherits System.Windows.Forms.Form Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click Dim frmTestForm As TestForm Utils.CreateForm("TestForm", frmTestForm) frmTestForm.ShowDialog() End Sub End Class Public Class Utils Public Shared Sub CreateForm(ByVal ts As String, ByRef f As Form) f = CType(CreateInstance(ts), Form) End Sub Public Shared Function CreateInstance(ByVal ts As String) As Object '//インスタンスを生成 'Dim sourcePageClassFullName As String = "" Dim type As System.Type = System.Type.GetType(ts) Dim obj As Object = type.InvokeMember(Nothing, _ System.Reflection.BindingFlags.CreateInstance, _ Nothing, Nothing, _ Nothing) Return obj End Function End Class
お礼
返事が遅くなりました。 >どうも、仕様のようです。 そうでした。ByValで渡すとポリモーがききます。 ByRefでFormを要求しているパラメータに FormAを与えてたとして、 メソッドの中でFormBに変更されてしまうと、 呼び元はFormA型なのに、FormBがはいってることになるという 変な状態になるような気がしてきました。 そのあたりの不都合を防止するための仕様のように感じました。 >関数を作る場合は、Return で値を返却するように >設計するのが標準的だと思っております。 私も標準的だと思っていたのですが、 事情があって、そうすると面倒な変更がほかのところで発生 するので、あったので、さけたかったのですが、 結局、あきらめて、そうしました。 どうも、ありがとうございました。