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