如何在vb.net中实现对类变量的重载

vb.net中重载变量

 

       重载函数是很正常的事,但有的时候,需要重载变量,如下例

 

       class Person

              public Name as string

       end class

 

       class Orgnization

              public head as Person

             

       end class

 

       Orgnization是一个类,它代表一个组织,它有一个head成员,代表这个组织的领导,属Person类型。

       现在我想从Orgnization派生一个类School,并使用它已经定义功能性函数,但我对Person类型的head不满意,因为它的字段太少了,只有一个Name,我想加一个Age字段,那么我该怎么办?

       C++中,这是很简单的事,只要把Orgnization设计成模板类就行了,但在VB中,这是个大难题——因为我实际上需要重载head变量。

       vb.net中引入了代理Delegate,以及隐藏Shadows概念,如果把它们和重载函数结合起来,可以实现对变量的重载,思路是这样的:

1、  Delegate使得函数可以被当成参数传递给另一个函数;

2、  函数是有返回值的,而且可以被重载,如果我让一个变量总是被一个函数指向,然后把这个函数重载,就可以通过重载函数,变相地重载这个变量,但有一个前提,即这个需要被重载的变量必须声明为Object类型或者其它的基类类型(如果能够确定重载类型总是这个基类类型的派生类型);

3、  通过Shadows把需要被重载的基类变量隐藏起来,然后在派生类中定义一个同名的派生变量(类型是被重载的变量的类型的派生类型);

4、  在基类中,凡是要引用被重载的变量,都不直接去引用,而是引用一个指向它的Delegate类型函数;

5、  在派生类中,把这个Delegate类型的函数重载,从而变相实现对基类变量的重载。

例:

 

Namespace p

    Public Class Person

        Public Name As String

    End Class

 

    Public Class Orgnization        '基类

        Public head As New Person   'head需要被重载

        Protected Delegate Function F_HEAD() As Person

 

        Protected Overridable Function GetHead() As Person  '关键:这个函数总是指向基类的head,

且可被重载

            Return head

        End Function

 

        Public sub DisplayHead()

MsgBox(GetHead().Name.ToString())     间接调用head变量

这里有个必须注意的地方:GetHead后必须带括号

                                   如果不想这么别扭,也很简单——把GetHead设计成

                                   属性

        End sub

        '…

    End Class

 

    Public Class SchoolHead                       'head将被重载成这个类型

        Inherits Person        

        Public Age As Integer

    End Class

 

    Public Class School

        Inherits Orgnization

        Public Shadows head As New SchoolHead  '先用Shadows隐藏基类的head,然后声明一个新的head

 

Protected Overrides Function GetHead() As Person    '重载这个函数,因而基类所有对head

的调用,原来是被映射到基类的GetHead

函数,现在则被映射到派生类的这个

函数。而这个函数是指向派生类的

head变量的,从而基类所有函数对原

来的head的调用全被重定向到派生

类的head上

            Return head

        End Function

        '…

End Class

 

现在做段代码来测试一下:

public sub t

        Dim p As New p.School

        p.head.Name = "Lj"

        p.head.Age = 100

        p.DisplayHead()

end sub

     结果显示的是lj,这说明DisplayHead最终作用到了派生类的head上——Shadows的语义说明中指出,基类的函数总作用在基类的被隐藏成员上,但这里用了一个小技巧,实现了重定向,使基类的函数作用到了派生类的成员上。

     从派生类的角度来看,重载head没有费太多代码,只是加了一个重载函数而已,关键是基类要设计好——应了那句老话:前人栽树,后人乘凉

 

这个例子说明了重载变量最基本的思路,但它也有明显的不足:

1、  派生类的GetHead()为Person类型,而不是SchoolHead类型,因而在派生类的函数中每次调用这个函数,还必须得用CType把它转换过来,很不方便。但如果认为这个派生类的head变量不会再被继承,就可以不用使用GetHead函数,而是直接用派生类的head就行了。但是如果认为这个派生类的head有可能还要被重载,那就没有办法,必须要转换。对于使用频繁的情况,当然还可以再设计一个私有函数(或属性),用它来包装CType,并返回SchoolHead类型,而在其它派生类的函数中,用这个私有函数再转一道,这可以让写代码轻松点;

2、  如果基类有一个公共属性Head(当然也可能是函数),它对外传递head对象,这就有点麻烦,因为派生类需要它对外传递SchoolHead类型的实例。这也有办法来解决:再用一个Shadows把基类的这个公共属性隐藏起来,并设计一个同名的Head属性,在Get段,可以这么写:

return head

如果基类中还有其它有用的代码,则可以在前面加几句:head=MyBase.Head …

3、  这个方法虽然在功能上实现了重载变量,但每调用一个重载变量(不论是在类的内部,还是外部)都要转好几个函数,程序性能明显要受影响,因此如果不是特别需要,也没必要这么干,不如直接粘代码。

4、  序列化问题。上面这个例子中,如果对School进行序列化,会发现在声明序列化器时出错,但是只要把基类Orgnization中的head成员声明为protected就可以解决问题。其实不光是这个应用,只要是用Shadows去隐藏基类变量,且这个基类变量是public 型,就会出现这个错误。我猜想原因是:虽然基类变量被隐藏了,但并非它就不存在了,事实上它还在内存里,但序列化器却没有发现这个问题,它只知道要对公共变量去进行检测,结果发现有两个同名的变量,所以就不知道怎么办了,只有报错。不过只要把这种变量声明为private或protected就行了——这也是一个缺点吧。

 

 

更进一步:

如果要重载数组怎么办?

也没有问题,思路是一样的

现在把上面的例子部分修改一下:

    Public Class Orgnization        '

        Public head(1) As Person    'head改为数组

        Protected Delegate Function F_HEAD() As Person()     注:很奇怪,Person不带括号竟然

也可以运行通过!!

 

        Protected Overridable ReadOnly Property GetHead() As Person() ' 返回值改成数组类型

            Get

                Return head

            End Get

        End Property

 

        Public Function DisplayHead()

            MsgBox(GetHead()(0).Name.ToString())     这里又是个别扭的写法,改属性就好点

        End Function

 

        Sub New()

            head(0) = New Person                           别忘了创建实例

            head(1) = New Person

        End Sub

        '…

    End Class

 

下面改派生类:

    Public Class School

        Inherits Orgnization

        Public Shadows head(1) As SchoolHead    '同样声明为数组

 

        Protected Overrides ReadOnly Property GetHead() As Person() 同上

            Get

                Return head

            End Get

        End Property

        '…

 

        Sub New()

            head(0) = New SchoolHead                  依然同上

            head(1) = New SchoolHead

        End Sub

End Class

 

测试代码:

sub t

        Dim p As New School

        head(0).Name = "Lj"

        head(0).Age = 100

        DisplayHead()

        MsgBox("OK")

end sub

 

结果正确,显示Lj,说明DisplayHead还是调用的派生类的数组,而不是基类的。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值