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

VS2003を使ってます。
VBはあまりよく知らなくて、
四苦八苦しています。

★1
Dim colorA = Color.Red

のようにAs Colorを記述するのを忘れている
のに、コンパイルが通ってました。
あれ?っと思ってました。

Option Strict On
をつけるとこれを抑止してくれるとわかり、
プロジェクトの設定で、つけるようにしました。

ところが、その弊害か?
引数として、Base型をとるメソッドにその派生型の
オブジェクトを引き渡すような呼び出しの
ところで、怒られてしまいました?
正確には、怒られたという1週間くらい前の記憶が
あります。
もしかしたら、ByValになってたからか?
BvRefだったら、OKなのか?
C++でポリモーを聞かすときは、Baseのポインタを
使うから。


これでは、ポリモーフィズムを効かすロジックが
書けないです。

★1のようなものを抑止しつつ、ポリモーフィズムを
効かすように、継承階層の上位の方向に対しては、
通常にキャストなしで、代入できる。
OOPとして、ごく普通のことをできるやり方を
教えて下さい。

A 回答 (2件)

お世話になります。



どうも、仕様のようです。
http://msdn2.microsoft.com/ja-jp/library/d26b27b …

> じゃ、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 が発生しているものと思われます。
    • good
    • 0
この回答へのお礼

返事が遅くなりました。
>どうも、仕様のようです。

そうでした。ByValで渡すとポリモーがききます。

ByRefでFormを要求しているパラメータに
FormAを与えてたとして、
メソッドの中でFormBに変更されてしまうと、
呼び元はFormA型なのに、FormBがはいってることになるという
変な状態になるような気がしてきました。
そのあたりの不都合を防止するための仕様のように感じました。

>関数を作る場合は、Return で値を返却するように
>設計するのが標準的だと思っております。

私も標準的だと思っていたのですが、
事情があって、そうすると面倒な変更がほかのところで発生
するので、あったので、さけたかったのですが、
結局、あきらめて、そうしました。

どうも、ありがとうございました。

お礼日時:2006/10/17 22:28

お世話になります。



> 引数として、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

この回答への補足

例えば以下のようなコードがあります。
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

補足日時:2006/07/23 13:00
    • good
    • 0
この回答へのお礼

さっそくありがとうございます。
↑ですが、うまく動いてるようです。
ただ、
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)が、今回問題になってる違いですね?これは、いかに??

よろしくお願いします。

お礼日時:2006/07/23 12:53

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