屏蔽基类成员
虽然派生类不能删除其继承的任何成员,但可以声明一个与基类成员签名相同的成员来屏蔽之。(注意方法的签名由名称和参数列表组成,不包括返回值类型)
要让编译器知道你在故意屏蔽继承的成员,可使用new操作符,否则会出现警告。
namespace TestConsole
{
class Human
{
public void Action()
{
Console.WriteLine("labour...");
}
}
class Student : Human
{
new public void Action()
{
Console.WriteLine("studing...");
}
}
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();
stu1.Action(); //运行结果为:studing...
Human stu2 = new Student();
stu2.Action(); //运行结果为:labour...
}
}
}
可以看到,如果是用基类类型来创建子类对象,就无法实现屏蔽,除非使用虚方法和覆写方法。
虚方法和覆写方法
虚方法即是基类中被标记为virtual的方法,在派生类中有与之对应的override方法,被称为覆写方法,或重写方法。多态就是基于重写机制的。
namespace TestConsole
{
class Human
{
public virtual void Action()
{
Console.WriteLine("labour...");
}
}
class Student : Human
{
public override void Action()
{
Console.WriteLine("studing...");
}
}
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student();
stu1.Action(); //运行结果为:studing...
Human stu2 = new Student();
stu2.Action(); //运行结果为:studing...
}
}
}
关于virtual和override修饰符有以下注意事项:
- 虚方法和与之对应的覆写方法必须有相同的可访问性,不能一个public而另一个private。
- 不能覆写static方法或非虚方法。
- 方法、属性、索引器、事件,都可以被声明为virtual和override。
抽象类与抽象成员
如果基类中存在这样一个方法,该基类没有实现它的意义,是专门用来给子类实现的,那么我们可以将其声明为抽象成员。
抽象成员是专门用来被覆写的成员,其有以下特征:
- 必须是一个函数成员,即常量和字段不能声明为抽象成员。
- 没有实现代码块,抽象成员的实现代码部分仅用一个分号表示。
- 必须用abstract修饰符标记。
- 不能是私有成员,可以是public或protected。
- 只能在抽象类中声明。
抽象成员在C++中被称为纯虚函数,因为相比普通的虚函数,其连实现代码块都没有。相比虚方法,抽象成员必须被覆写,前者覆写是可选的,而后者是必须的。
有4种类型的成员可以声明为抽象成员:方法、属性、事件、索引器。
抽象类则是专门用来被继承的类,抽象类只能被用作其他类的基类,其不能创建实例对象,且要和抽象成员一样,使用abstract声明。抽象类中可以包含抽象成员或非抽象成员,但抽象成员只能存在于抽象类中。
namespace TestConsole
{
abstract class Animal
{
public abstract void Action();
}
class Human : Animal
{
public override void Action()
{
Console.WriteLine("labour...");
}
}
class Program
{
static void Main(string[] args)
{
Human man = new Human();
man.Action();
}
}
}
抽象类与开闭原则
SOLID设计原则中的“开闭原则”:如果不是为了修复bug或增加功能,尽量不要去修改类的代码,特别是函数成员的代码;我们应该封装那些稳定的、确定的、不变的成员,而那些不稳定的、不确定的、随时可能会改变的成员应该声明为抽象成员,留给子类去实现。