继承
- 继承(以及封装和多态性)是面向对象的编程的三个主要特征之一。
通过继承,可以创建新类,以便重用、扩展和修改在其他类中定义的行为。
其成员被继承的类称为“基类”,继承这些成员的类称为“派生类”。 - 派生类只能有一个直接基类。
- 但是,继承是可传递的。
如果 ClassC 派生自 ClassB,并且 ClassB 派生自 ClassA,则 ClassC 将继承在 ClassB 和 ClassA 中声明的成员。
// 基类
class Person
{
public string name;
public int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void read()
{
Console.WriteLine("Person can read.");
}
}
// 派生类
class Student: Person
{
public int id;
public Student(string name, int age, int id) : base(name, age) // 如果基类的构造函数没有参数,则派生类的构造函数不需要使用base.
{
this.id = id;
}
public new void read() // 这里也可以不写 “new”, 但是VS会发出警告
{
Console.WriteLine("Student can read.");
}
public void study()
{
base.read();
Console.WriteLine("Then can study.");
}
}
class Program
{
static void Main(string[] args)
{
Student stu = new Student("joe", 20, 114);
stu.study();
}
}
// 运行结果:
Person can read.
Then can study.
多态
- Hide base class members with
new
members
– 如果希望派生类具有与基类中的成员同名的成员,则可以使用 new 关键字隐藏基类成员;
– new关键字可加可不加,但不加的话,VS会发出警告;
– 在派生类的方法上使用new关键字时,不需要在基类做任何改动,就像上面的例子所示;
– 通过将派生类的实例强制转换为基类的实例,可以访问隐藏的基类成员,如下例:
Student B = new Student(...);
B.read(); // Calls the new method.
// Student can read.
Person A = (Student)B;
A.read(); // Calls the old method.
// Person can read.
Virtual
members
– 仅当基类成员声明为 virtual 或 abstract 时,派生类才能重写基类成员;
– 派生成员必须使用 override 关键字显式指示该方法将参与虚调用。
– 当派生类重写某个虚拟成员时,即使该派生类的实例被当作基类的实例访问,也会调用该成员,如下所示:
Student B = new Student("joe", 20, 114);
B.read(); // Calls the new method.
// Student can read.
Person A = (Person)B;
A.read(); // Also calls the new method.
// Student can read.
- Hide base class members with new members
– 无论在虚拟成员和最初声明虚拟成员的类之间已声明了多少个类,虚拟成员都是虚拟的。 如果类 A 声明了一个虚拟成员,类 B 从 A 派生,类 C 从类 B 派生,则不管类 B 是否为虚拟成员声明了重写,类 C 都会继承该虚拟成员,并可以重写它。 - Access base class virtual members from derived classes
– 已替换或重写某个方法或属性的派生类仍然可以使用 base 关键字访问基类的该方法或属性,如上例中的study方法。
替换(new)与重写(override)
在 C# 中,派生类可以通过关键字new
或override
包含与基类方法同名的方法。
- 如果派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,该方法将如同存在 new 关键字一样执行操作;
- 如果派生类中的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法;
- 如果派生类中的方法前面带有 override 关键字,则派生类的对象将调用该方法,而不是调用基类方法;
- 若要将 override 关键字应用于派生类中的方法,必须以虚拟形式(virtual或abstract)定义基类方法;
- override、virtual 和 new 关键字可以用于方法、属性、索引器(indexer)和事件中。
virtual 与 abstract
virtual 关键字
- 可用于修饰方法,属性,索引器和事件;
- 被修饰的方法有其自己的实现;
- 在派生类中可以重写virtual方法的实现;
- 不能和static, abstract, private和override修饰符同时使用。
abstract 关键字
- 可用于修饰类, 方法, 属性, 索引器和事件;
- The abstract modifier indicates that the thing being modified has a missing or incomplete implementation;
(对于方法来说和属性,没有具体实现;
对类来说,类中有些方法没有被实现或这整个类都没有具体实现。
所以如果一个类中有成员是抽象的,则其一定是抽象类;但一个抽象类中不一定有抽象的成员)
抽象类
- 不能被实例化,只能作为其他类的基类;
- 类中可以包含抽象和非抽象成员;
- 不能同时使用sealed关键字修饰该类;
- 派生自抽象类的类必须实现该抽象类所有的非私有成员;
- 如果抽象类实现了某个接口,则它必须实现接口中的所有成员。
抽象方法
- 抽象方法即是隐式的虚拟方法(virtual),之后在具体实现时要用override关键词修饰;
- 抽象方法只存在与抽象类中;
- 抽线和方法没有具体实现,所以没有花括号和函数体,直接以分号结尾,例如:
public abstract void MyMethod();
抽象属性
- 不能与static或virtual关键字同时使用;
- An abstract inherited property can be overridden in a derived class by including a property declaration that uses the override modifier;
- 其余和抽象方法类似。
参考资料
Polymorphism (C# Programming Guide)
Versioning with the Override and New Keywords (C# Programming Guide)
virtual (C# Reference)
abstract (C# Reference)