一、重载
方法通过形式的变化,达到重载。
通过重载,创建同名的几个方法,每个方法接收不同的参数或不同类型的参数。
如下:
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
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和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
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 运算符当作匹配对。 这意味着如果您定义其中一个运算符,则还必须定义另外一个。