这几天正在做GDI+的一个练习程序,参考了《VC#.NET开发交互式CAD系统》这本书,书中的参考方法创建了许许多多的类和一个接口。开始我还在想接口有啥作用啊?是不是有点多此一举。然后就去网上搜索了一下接口的意义,个人感觉受益颇多,顺便把以前搜索过的内容翻出来记录总结一下。
我相信一定有很多和我一样的同学,对接口、虚方法、抽象类感觉很模糊、很生疏。这些东西用起来好像很简单,定义接口,里面包含方法,但没有方法具体实现的代码,然后在继承该接口的类里面要实现接口的所有方法的代码。
我在网上看到了一个简单易懂的例子:
首先,我们先定义一个接口:(接口的关键字interface)
public interface IBark
{
void Bark();
}
再定义一个类,继承于IBark,并且必需实现其中的Bark()方法
public class Dog:IBark
{
public Dog()
{}
public void Bark()
{
Consol.write("汪汪");
}
}
Dog的一个实例,并调用Bark()方法
Dog 旺财=new Dog();
旺财.Bark();
试想一样:
若是想调用Bark()方法,只需要在Dog()中声明这样的一个方法不就行了吗,干什么还要用接口呢?
因为接口中并没有Bark()具体实现.真的实现还是要在Dog()中.那么使用接口不是多此一举吗?
我做练习是就是这样想的,代码如下。究竟是为啥呢?
还有人是这样说的:从接口的定义方面来说,接口其实就是类和类之间的一种协定,一种约束.还拿构会叫的例子来说.所有继承了IBark接口的类中必需实现Bark()方法.那么从用户(使用类的用户)的角度来说,如果他知道了某个类是继承于IBark接口,那么他就可以放心大胆的调用Bark()方法,而不用管Bark()方法具体是如何实现的.比如,我们另外写了一个类。
public class Cat:IBark
{
public Cat()
{}
public void Bark()
{
Consol.write("喵喵");
}
}
当用户用到Cat类或是Dog类的时候,知道他们继承于IBark,那么不用管类里的具体实现,而就可以直接调用Bark()方法,因为这两个类中肯定有关于Bark()方法的具体实现.
如果我们从设计的角度来看.一个项目中用若干个类需要去编写,由于这些类比较复杂,工作量比较大,这样每个类就需要占用一个工作人员进行编写.比如A程序员去定Dog类,B程序员去写Cat类.
这两个类本来没什么联系的,可是由于用户需要他们都实现一个关于”叫”的方法.
这就要对他们进行一种约束,让他们都继承于IBark接口。
说了这么多,其目的就是统一管理,再者就是方便他人调用,再加上就是避免有些人会漏掉这个方法。(漏掉就会报错哦,我就是刚开始一直纳闷为啥这报错了)
----------------------------------------------------------------------------------------------------------------------------------------------------------
再者就是虚方法:
当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法,虚方法是使用关键字virtual
声明的,虚方法可以在不同的继承类中有不同的实现,即为基类中定义的允许在派生类中重写的方法。
访问修饰符 virtual 返回值类型 函数名(参数)
{
函数体;
}
调用上,使用子类构造的对象调用虚方法,就会调用子类的方法,使用父类构造的对象,就会调用父类的方法
1、在基类中声明的虚方法一般在派生类中对其进行调用,会运用到base
关键字
(当输入访问修饰符和override
后,系统会自己弹出我们刚才编写的虚方法,直接进行选择即可)
class Person
{
public virtual void XXX()// 虚方法是在方法前加virtual关键字,对方法进行声明
{
Console.Write("Hello World");
}
}
class Boy:Person
{
public override void XXX()//虚方法调用
{
base.XXX();
...
}
}
//在运行时调用
static void Main(string[] args)
{
Person person = new Person();//虚拟类其实指的是正常类中的虚拟方法,所以虚拟类可以直接使用实例,这是与抽象类不同的一点,它不会像抽象类一样进行报错!!!
Boy boy = new Boy();
boy.XXX();//Hello World
}
这里注明三点
1、虚拟函数和正常函数无区别。
2、当用virtual
修饰后,不允许再有 static
、abstract
或者 override
修饰符。
3、子类继承虚拟类可以实现虚拟方法也可以不实现虚拟方法,如下例子:
class Person
{
public virtual void XXX()
{
Console.WriteLine("我有一千万给你!");
}
}
class Boy : Person
{
public override void XXX()
{
Console.WriteLine("我不要你的钱");
}
public void YYY()
{
Console.WriteLine("我自己要努力,自己挣钱");
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();//实例化的虚方法类
Boy boy = new Boy();//实例化的子类。记得实例化!千万不能忘记哟
boy.XXX();//调用了子类的方法
boy.YYY();
Console.ReadLine();
}
}
//结果: 我不要你的钱
我自己要努力,自己挣钱
总结一下虚方法的作用:1、增加code的可维护性,脉络清晰、有条理。2、允许 子类 进行重写。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
最后是抽象类
首先,抽象类与其它的类有什么区别呢?
抽象类是不能够被实例化的。如果一个类中包含有抽象方法,那么这个类一定要声明为抽象类。同时,抽象方法一定需要在子类中重写,让抽象方法成为一个具体的实实在在的方法。
我们还以猫和狗为例子,假如我们不单单有猫和狗,还有鲨鱼、蚯蚓、猫头鹰等,他们有一个共性:是动物animal
animal仅仅是一个词而已,他不代表任何的具体对象,它只是代表所有动物所拥有的共同特征,所以animal类是根本不可能被实例化的。
同时,如果所有动物都必须声明"叫"这样一个方法的话,那么,我们可以在animal类中声明一个抽象方法bark(),因为抽象方法是必须在子类中重写的,所以这就限制了所有继承自animal类都必须重写bark()方法。
abstract class Animal //声明Animal为抽象类
{
protected abstract void Bark(); //声明Shout()方法为抽象方法,那么所有继承Animal类的子类都必须重写Bark()方法
}
//声明Dog类,继承自Animal类
class Dog:Animal
{
protected override vod Bark()
{
response.write("woof woof");
}
}
一个抽象类可以包含抽象和非抽象方法,当一个类继承于抽象类,那么这个派生类必须实现所有的基类抽象方法。
一个抽象方法是一个没有方法体的方法。
//拾取图元
abstract public bool Pick(PointF aPos);
//平移图元
abstract public void Move(Graphics g, PointF basePos, PointF desPos);
-
抽象方法有以下特征:
1.一个抽象方法可以看作是一个虚函数。
2.抽象方法的声明只能在抽象类中。
3.因为抽象方法声明只提供一个无实现的方式,没有方法体
4.方法体的实现被覆写方法提供,覆写方法是一个非抽象类的成员。
5.抽象属性的行为和抽象方法相像,除了不同的声明形式。//一个抽象属性能够通过派生类使用 override 实现
6.在一个静态属性中使用abstract 是一个错误。
-
抽象类具有以下特征:
1.抽象类不能被实例化。
2.抽象类可以包含抽象方法和访问器
3.不能把抽象类用密封(sealed)来修饰,那就意味着类不能被继承,这违反抽象类被继承的原则。
4.一个派生于一个抽象类的非抽象类必须包括所有的继承来的抽象方法和访问器的实现
5.在方法和属性中使用abstract 关键字意味着包含它们的实现。