VB.net学习笔记(八)重载与共享


一、重载

       方法通过形式的变化,达到重载。

       通过重载,创建同名的几个方法,每个方法接收不同的参数或不同类型的参数。

      如下:

Public Sub Walk()       '1、重载,无参数
    RaiseEvent Walked(0)
End Sub

Public Sub Walk(ByVal Distance As Integer) '2、重载,带一个参数
    mintTotalDistance += Distance
    RaiseEvent Walked(Distance)
End Sub

Public Sub Walk(Optional ByVal Distance As Integer = 0) '3、上面1和2简化写成一个
    mintTotalDistance += Distance
    RaiseEvent Walked(Distance)
End Sub

       Optional可以合并前两个重载,它的灵活性并不大,只能选择不选或者选择。重载还可以便参数个数不同,或类型不同。

       OverLoads 关键字在方法的简单重载中并不需要使用。但,把重载与继承结合时,就需要使用它。






二、重载技巧

        为什么.net会根据同名来确定方法的重载呢?

      

      1、方法签名

        .net通过方法签名来确定重载方法分属不同的方法,从而实现运行。因为完全一样的方法编译器会提示出错。

        方法签名:由方法的名称、参数的数据类型来确定。

         Public  Function  Add() As  Integer    ‘方法签名为: f()      f表示方法名,()表示参数

         Public  Function  Add(ByVal  a  As Double) As  Integer  '方法签名为: f(double)     表示参数为double类型

          Public  Function  Add(ByVal  a  Double,byval b as integer ) As  Integer  '方法签名:f(double,integer)

        

          注意:(1)返回值(类型)不是方法签名的一部分。两个方法完全相同,只是返回值类型不一样时,它们的方法签名是一样的。

                                                              这样的不能重载,且编译会出错。

                        (2)参数的名称不重要,只在意它的类型。编译器只看类型,忽略参数的名称。

                        (3)传递方式不重要。编译器不会在意是按值传递还是按引用传递。


          2、组合重载与可选。

          重载比可选参数更为灵活。可选参数也有优势,主要在于可提供默认值。

         Public Sub DoWork(Byval  x as integer,optional byval y as integer=0 )  '1
         Public Sub DoWork(Byval  x as integer) '2
         Public Sub DoWork(Byval  x as String) '3

         上面1和2同时出现会出错,因为1的签名是f(integer),f(integer,integer)  ,2的签名是f(integer).。这样出现了相同的签名,故出错。

         上面1和3同时出现不会出错,因为分别是:f(integer),f(integer,integer),f(string)。

          另外:1和3的同时出现,智能提示会提示是3种变体,内部是当作两个方法的重载,这与创建3个不同的重载方法来匹配3个签名是不同的。





二、重载构造函数

       用New可构造(创建)对象(实例),而New后面跟不同的参数,就会形成构造函数的重载。  

      下面是构造函数的重载,所带的参数不同,形成了不同的签名:

    Public Sub New(Optional ByVal Name As String = "", Optional ByVal BirthDate As Date =#1/1/1900#)
        mstrName = Name
        mdtBirthDate = BirthDate

        Phone("home") = "555-1234"
        Phone("work") = "555-5678"
        sintCounter += 1
        RaiseEvent NewPerson()
    End Sub


  Public Sub New(ByVal Name As String, ByVal BirthDate As Date)
    mstrName = Name
    mdtBirthDate = BirthDate

    Phone("home") = "555-1234"
    Phone("work") = "555-5678"
    sintCounter += 1
    RaiseEvent NewPerson()
  End Sub






二、共享变量、共享方法、共享事件。

       前面都是通过“实例方法”来完成,即必须有一个实例(对象)才能完成工作。

       有时,一此功能无法预测类中实例,也是有实例,也许没有实例,也许无法预知实例(对象)的个数。

       于是产生了一个不依赖对象(实例)的变量、方法、事件。

        这种变量、方法,事件,属于所有对象共享,不属性单独的具体对象,它属于类,被类的所有实例共享。


        用Shared来标记,它属性类,而不属于某个对象。比如,一共产生了多少个对象?

        

        1、共享变量

        共享变量只属于类的变量,用Shared标记。类似于C++的Static数据成员 。

        如下:每构造(创建)一个对象(实例)时,就会自动增加sintCounter的计数。

Public Class Person
    '.......其它代码
    Private Shared sintCounter As Integer   '共享变量

    Public Sub New(ByVal Name As String, ByVal BirthDate As Date)
        mstrName = Name
        mdtBirthDate = BirthDate

        Phone("home") = "555-1234"
        Phone("work") = "555-5678"
        sintCounter += 1          ’每增加一个对象自动计数
        RaiseEvent NewPerson()
    End Sub

    Public Sub New()
        Phone("home") = "555-1234"
        Phone("work") = "555-5678"
        sintCounter += 1          '自动统计计数
        RaiseEvent NewPerson()
    End Sub
    
    '......
End Class



          2、共享方法

          同理,共享方法也属于类,不属于任何对象,不能访问任何对象中的任何实例变量。

           如果想访问其它实例,只能通过传参数的方法间接取得。否则将出错。

                 简单地说:  普遍性不能访问个例,个例可以访问普通性。


          共享方法属于类,当然可以访问类中其它的共享变量和方法,因为他们级别相同。


          共享方法,同样是在前加上Shared关键字即可。


          这其实和C++的概念相同,复习一下:

共享数据(变量)与共享方法分别对应C++的静态数据成员和静态成员函数。
同样共享方法属性类,它在内存同普通方法一样,只有一个副本。
C++中


1、静态成员函数为什么没有this指针?
this指的是当前对象,而静态成员函数是属于类的,要用类来访问


2、静态成员函数为什么只能访问静态成员?
静态成员函数不接受隐含的this自变量。普通成员是根据this指针定位函数位置,
因此无法确定普通成员的位置,它就无法访问自己类的非静态成员。
   当然可以变向访问一些东西,比如声明成员函数全为静态,就可访问。
   另外,在静态成员函数中接收对象参数,通过对象参数来访问对应的普通成员。


3、为什么虚函数必须是非静态成员函数?
因为虚函数是动态绑定的,也就是在派生类中可以被覆盖的。而静态成员函数的定义
本身就是静态绑定的,这两者相互矛盾,所以不能是静态成员函数。



        3、共享属性

        共享属性,本质上也是共享方法,它们规律相同。

         

        故也是在其中加上Shared即可表明是共享属性。

    Public Shared ReadOnly Property PersonCount() As Integer
        Get
            Return sintCounter
        End Get
    End Property

           无论是共享变量、共享方法、共享属性,它们都是通过类名进行访问:

        Dim myPerson As Person
        myPerson = New Person
        myPerson = New Person
        myPerson = New Person
        MessageBox.Show(Person.PersonCount()) '1、标准写法,共享数据通过类名访问
        MessageBox.Show(PersonCount())        '2、错误,未限定范围(不知是哪个类的)
        MessageBox.Show(myPerson.PersonCount()) '3、非标准(发出警告)因模糊了实例与类的共享成员(不推荐)

          下面是共享属性访问共享变量:(这个共享变量翻译成共享数据估计更好理解)

    Public Shared ReadOnly Property PersonCount() As Integer    '只读属性PersonCount
        Get
            Return sintCounter
        End Get
    End Property
          下面是共享方法,通过传递参数的方法,访问具体的实例:

    Public Shared Function CompareAge(ByVal Person1 As Person, ByVal Person2 As Person) As Boolean
        Return Person1.Age > Person2.Age
    End Function
           共享属性的另一例:

    Public Shared ReadOnly Property RetirementAge() As Integer   '只读属性RetirementAge
        Get
            Return 62
        End Get
    End Property




           4、共享事件

           共享事件的声明定义:          

    Public Shared Event NewPerson()

          共享事件可以在实例方法或共享方法中引发。

          普通事件只能在普通方法中引发,而普通事件不能在共享方法中引发(因为共享方法中无法确定针对的是哪一个普通的事件)。

          如图:大方框表示方法,小方框表示插入其内的引发事件(RaiseEvent)


          下面是普通方法引发共享事件:

Public Class Person
  '.........
  Public Shared Event NewPerson()

  Public Sub New(ByVal Name As String, ByVal BirthDate As Date)
    mstrName = Name
    mdtBirthDate = BirthDate

    Phone("home") = "555-1234"
    Phone("work") = "555-5678"
    sintCounter += 1
    RaiseEvent NewPerson()   '普通方法调用共享事件
  End Sub

  Public Sub New()
    Phone("home") = "555-1234"
    Phone("work") = "555-5678"
    sintCounter += 1
    RaiseEvent NewPerson()
  End Sub
  '..........
End Class

              复习:事件其实就类似于回调函数。

                           一般调用方法后,就不再进行,而回调函数,是在调用方法后,该方法再次调用另一个函数(事件)。

               如图:

               构造中有引发事件,通过AddHandler把构造中的事件与客户中的另一个方法联系起来。于是调用构造时就会引出客户中的方法。




       

            5、共享构造函数。

            构造函数本身就是在创建实例之前。

            而共享构造函数更是在构造函数之前,在它的生命中,只被调用一次,且在第一次使用该类(不是实例)之前调用。

         

           共享构造函数不能直接调用,因此不能接收任何参数,它只能与类的共享变量或者其它共享方法进行交互(访问)。


         通常,它用于初始化对象内部的共享字段。比如计算类的对象的个数,想把初始计数设置为0 

    Private Shared sintCounter As Integer
    Shared Sub New()
        sintCounter = 0
    End Sub





三、运算符重载。

        对象的+,-,X,等运算并没有定义,怎么办,可利用现有的运算符,通过重载的方法,实例类似基本类型的运算方式。


        运算符重载,用Operator来指明,且必须用Shared进行限定。(类似于C++的友元重载)

         

       而且VB.net的运算符重载很怪,很多运算符必须成对出现重载,否则出错。

       比如:=和<>,>和<等必须成对出现重载:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim a As Person = New Person(3)
        Dim b As Person = New Person(4)
        a = a + 3
        TextBox1.Text = a.show()
    End Sub
End Class


Public Class Person
    Private b As Int32
    Public Sub New(Optional d As Int32 = 0)
        b = d
    End Sub
    Public Shared Operator +(ByVal f As Person, ByVal d As Int32) As Person
        f.b = f.b + d
        Return f
    End Operator
    Public Shared Operator =(ByVal c As Person, ByVal d As Person) As Boolean
        Return c.b = d.b
    End Operator
    'Public Shared Operator >(ByVal c As Person, ByVal d As Person) As Boolean
    '    Return c.b > d.b
    'End Operator
    'Public Shared Operator <(ByVal c As Person, ByVal d As Person) As Boolean
    '    Return c.b < d.b
    'End Operator
    Public Shared Operator <>(ByVal c As Person, ByVal d As Person) As Boolean
        Return c.b <> d.b
    End Operator
    Public Function show() As Int32
        Return b
    End Function
End Class

          另外,对于CType运算符的重载,还必须出现Narrowing或者Widening,用来指明取值范围是扩大还是收缩。

    Public Shared Narrowing Operator CType(ByVal name As String) As Person
        Dim obj As New Person   'Ctype必须带有Narrowing(收缩)或Widening(扩展)来指明类型的变化范围
        obj.Name = name
        Return obj
    End Operator
    Public Shared Widening Operator CType(ByVal obj As Person) As String
        Return obj.Name 'Person->String转换,由窄转向宽,扩展,故用windening
    End Operator




           运算符重载的说明:

         1、= 和<>      等于与不等于,二元运算,必须成对出现。

          2、>和<        大于和小于,   二元运算,必须成对出现重载。

          3、>=和<=     大于等于和小于等于,二元,必须成对出现。

          4、IsFalse和IsTrue     布尔转换,只能出现在重载中,用于支持AndAlso,OrElse。接收一个对象。必须成对出现。

          5、CType           类型转换,接收一个参数(返回值是另一转换类型),必须与Narrowing或Widening结合。

          6、+和-                加与减,一元或二元。(一元:a+=b,二元:a+b)

          7、*,/,\,^,Mod             乘、除、指数、整除、取余,二元运算。

          8、&                       连接,二元(a&b)

          9、<<和>>          位移。二元(a>>b),第二个参数必须是integer类型(指定位移数目)

          10、And,Or, Xor         逻辑比较(或位操作),二元(返回值是布尔是逻辑,返回值是其它数据类型是按位)

          11、Like                    模式比较。二元(a  Like b)


          AndAlso与OrElse

         这比原And和Or更进步了,它们实现最短路径实现法,只要第一个能确定结果则不再进行第二比较,只有第一个不能确定全部结果时

         才进行第二步,因为实现方式较为最短。


          AndAlso与OrElse的重载。

         百度N久没看到实例。查了MSDN,翻书几本没找到实例。

         试着写了一个简单的重载它们的例子:

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim obj1 As Person = New Person(0)
        Dim obj2 As Person = New Person(1)
        If obj1 AndAlso obj2 Then
            TextBox1.Text = True
        Else
            TextBox1.Text = False
        End If
    End Sub
End Class
Public Class Person
    Private intAge As Int32
    Public Property Age() As Int32
        Get
            Return intAge
        End Get
        Set(value As Int32)
            intAge = value
        End Set
    End Property
    Public Sub New(Optional a As Int32 = 0)
        intAge = a
    End Sub
    Public Shared Operator And(ByVal a As Person, ByVal b As Person) As Person '重载And注意返回对象(不是boolean)
        If a.intAge And b.intAge Then                                          '这样就为下面短路判断isFalse做好准备
            Return New Person(1)
        Else
            Return New Person(0)
        End If
    End Operator
    Public Shared Operator IsFalse(ByVal a As Person) As Boolean      '重载IsFalse(必须配套重载IsTrue)
        Dim b As Boolean = Not CType(a.intAge, Boolean)
        Return b
    End Operator
    Public Shared Operator IsTrue(ByVal a As Person) As Boolean
        Dim b As Boolean = CType(a.intAge, Boolean)
        Return b
    End Operator
End Class

        可以看到,这两个重载不能直接重载,只能间接通过IsFalse,IsTrue及And和Or的重载来实现。

       重载实现的方法是:

      1、AndAlso重载:   (1)重载And(接收两个自定义类型的对象参数),并返回一个自定义类型的对象作为结果。

                                                       注意这里返回不是Boolean,因为这个返回值为下面二步作准备。

                                            (2)重载IsFalse,使用自定义类型的对象参数,返回值为Boolean

       2、OrElse重载:(1)重载Or(接收两个自定义类型的对象参数),并返回一个自定义类型的对象作为结果。

                                                       注意这里返回不是Boolean,因为这个返回值为下面二步作准备。

                                            (2)重载IsTrue,使用自定义类型的对象参数,返回值为Boolean


为什么要这样定义重载呢?看一下andalso,orelse的定义:

Public Function AndAlso(x as Boolean, y as Boolean) As Boolean 
    Return IIf(x, x And y, False) 
End Function 
  
Public Function OrElse(x as Boolean, y as Boolean) As Boolean 
    Return IIf(x, True, x Or y) 
End Function

         通过And或Or先判断一下(IsTrue或IsFalse),来确定AndAlse或OrElse。


      另外:

不能在代码中显式调用 IsFalse,但 Visual Basic 编译器可以用它从 AndAlso 子句生成代码。 如果您定义一个类或结构,然后在 AndAlso 子句中使用这种类型的变量,则必须在该类或结构上定义 IsFalse

编译器将 IsFalse 和 IsTrue 运算符当作匹配对。 这意味着如果您定义其中一个运算符,则还必须定义另外一个。






  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值