多态
先来看一下例子:
using System;
class Fruit
{
public void PutFruit()
{
Console.WriteLine("父类的PutFruit方法被调用");
}
}
class Apple:Fruit
{
public void PutFruit()
{
Console.WriteLine("子类的PutFruit方法被调用");
}
}
class Program
{
static void Main(string[] args)
{
Fruit fruit = new Apple();
fruit.PutFruit();//调用的是父类的方法
}
}
父类Fruit和子类Apple有一个相同的方法PutFruit,像我们知道,如果是父类对象调用PutFruit,那么就是父类的PutFruit方法被执行,子类对象调用,就是子类的PutFruit方法被执行。
而上面那个例子,用父类定义了fruit,然后用子类来实例化,这样再调用PutFruit,执行的是子类的方法,还
是父类的呢。答案是父类的。
而多态呢,在这个情况下调用的是子类的方法,也就根据父类指向子类对象的不同,而调用相应子类的PutFruit方法,不过多态得用虚函数来实现。
也就是下面这个模式:
using System;
class Fruit
{
public virtual void PutFruit()//虚方法,用于多态
{
Console.WriteLine("父类的PutFruit方法被调用");
}
}
class Apple:Fruit
{
public override void PutFruit()//override和父类虚函数相呼应。
{
Console.WriteLine("Apple子类的PutFruit方法被调用");
}
}
class Banana:Fruit
{
public override void PutFruit()
{
Console.WriteLine("Banana子类的PutFruit方法被调用");
}
}
class Program
{
static void Main(string[] args)
{
Fruit fruit = new Apple();
fruit.PutFruit();
fruit = new Banana();
fruit.PutFruit();
}
}
其中被override修饰的方法,在父类中与其相同的方法,必须被virtual或abstract关键字修饰,而父类中被virtual
修饰的方法,它子类对应的方法,也必须被virtual修饰,不然无法实现多态。另外这也是方法的重写。或者说是通过方法的重写来实现
多态的。
抽象类。
用abstract关键字修饰的类,就叫做抽象类,抽象类里可以有抽象方法,也可以没有。它们之间的区别就是
方法前有没有abstract关键字,而且抽象方法没有执行语句,因为它本身不会被调用,只是给子类重写的。
另外,抽象类不能被实例化。
看下例:
using System;
abstract class Fruit//抽象类
{
public abstract void PutFruit();//抽象方法
}
class Apple:Fruit
{
public override void PutFruit()//override和父类虚函数相呼应。
{
Console.WriteLine("Apple子类的PutFruit方法被调用");
}
}
class Banana:Fruit
{
public override void PutFruit()
{
Console.WriteLine("Banana子类的PutFruit方法被调用");
}
}
class Program
{
static void Main(string[] args)
{
Fruit fruit = new Apple();//new Fruit()是无法通过的,抽象类不能实例化
fruit.PutFruit();
fruit = new Banana();
fruit.PutFruit();
}
}
委托
因为C#没有指针这个概念,所以函数指针也没有,那么委托就是代替函数指针的,它的存在跟C++函数指针一样。
先来看一下C++函数指针的例子:
#include<iostream.h>
void OutApple(int Num)
{
cout<<Num<<endl;
}
typedef void (*pOutApple)(int Num);
void (* poa)(int Num);
int main(int argc, char* argv[])
{
pOutApple pOutAle=OutApple;
pOutAle(550);
poa=OutApple;
poa(650);
return 0;
}
上面void (* poa)(int Num)这一句就是定义了一个函数指针,指向OutApple函数,
而typedef void (*pOutApple)(int Num)这一句,就是给函数类型定义取别名,这样pOutApple就是一个OutApple函数指针类型,用pOutApple定义的变量,就是一个可以指向OutApple函数的函数指针。
而C#的委托就是跟这个相关,可以这么说,它是用delegate代替了C++的typedef。
例子:C#委托的定义
using System;
delegate void pOutApple(int Num);//定义委托
class Apple
{
public void OutApp(int Num)
{
Console.WriteLine("{0}", Num+500);
}
}
class Program
{
static void OutApple(int Num)
{
Console.WriteLine("{0}", Num);
}
static void Main(string[] args)
{
pOutApple pOutAle = OutApple;//指向OutApple方法
//另外指向OutApple方法,也可用这种:pOutApple pOutAle=new pOutApple(OutApple);实例化
pOutAle(500);
Apple apple = new Apple();
pOutAle = apple.OutApp;//指向Apple类里的OutApp方法
pOutAle(500);
}
}
多播委托就是可以同时执行多个方法,用'+'号把实例化的委托合并起来。
看下例:
using System;
delegate void pOut();//定义委托
class Program
{
static void FirOut()
{
Console.WriteLine("第一个FirOut方法");
}
static void SecOut()
{
Console.WriteLine("第二个SecOut方法{0}");
}
static void ThiOut()
{
Console.WriteLine("第三个ThiOut方法");
}
static void Main(string[] args)
{
pOut pot1 =new pOut(FirOut);//第一个FirOut方法
pOut pot2 = new pOut(SecOut);//第二个SecOut方法
pOut pot3 = new pOut(ThiOut);//第三个ThiOut方法
pot1 += pot2;//合并
pot1 += pot3;
pot1();//一起调用三个方法
Console.WriteLine("删除掉pot2,也就是SecOut方法");
pot1 -= pot2;//删除一个方法
pot1();//调用两个方法
}
}
记住,合并的方法必须是一致的,它的参数,返回值等。
接口
接口的特性跟类很相似,可以被继承,里面也有方法,这里说一下它们的区别。
接口里不能有普通的成员变量(字段),但可以有属性成员(也就是set,get模式的变量),但在接口中,这些成员,方法,或者属性成员,都只是一个空壳,没有实际实现。
都是由继承它的类,或者结构体来具体实现的。
C++中,一个类可以继承多个类,但C#中只可以单继承,似乎关于类继承方面C#没有C++灵活,但C#的类可以继承多个接口,算是弥补了这个不足吧。
例子:接口的实现
using System;
//第一个接口IApple,interface关键字定义接口
interface IApple
{
void OutApple(int Num);
}
//第二个接口IBanana
interface IBanana
{
void OutBanana(int Num);
}
//继承两个接口,类里面必须实现继承的接口方法
class Outnum:IApple,IBanana
{
//实现接口方法
public void OutApple(int Num)
{
Console.WriteLine("{0}", Num);
}
public void OutBanana(int Num)
{
Console.WriteLine("{0}",Num);
}
}
class Program
{
static void Main(string[] args)
{
Outnum outnum = new Outnum();
outnum.OutApple(500);
outnum.OutBanana(1000);
}
}
显式接口
怎么定义显式接口,在继承接口的类中,用接口成员全权名的方式定义接口,所谓全权名,比如接口IBanana,
它里面的OutBanana方法的全权名就是IBanana.OutBanana;
那么显式接口里面的方法是怎么样调用的呢,通过接口调用,也就是接口定义的对象通过继承它的类来实例化,再调用接口里的方法。
例子:显式接口的定义以及使用
using System;
//第一个接口IApple,interface关键字定义接口
interface IApple
{
void OutApple(int Num);
}
//第二个接口IBanana
interface IBanana
{
void OutBanana(int Num);
}
//继承两个接口,类里面必须实现继承的接口方法
class Outnum:IApple,IBanana
{
//显式接口的定义,显示接口的方法不能用public修饰
void IApple.OutApple(int Num)
{
Console.WriteLine("{0}", Num);
}
void IBanana.OutBanana(int Num)
{
Console.WriteLine("{0}",Num);
}
}
class Program
{
static void Main(string[] args)
{
IApple iapple = new Outnum();
iapple.OutApple(500);
IBanana ibanana = (IBanana)iapple;//其实指向的还是new Outnum()
ibanana.OutBanana(1000);
}
}
另外接口不能通过继承类的方式来继承,例如一个Outnum类继承了一个接口IApple,那么Program类继承Outnum类的话,Program类里是没有IApple里的方法的,如果要使用,还需要自己来继承接口,并实现。