C# 类继承(知识要点归纳总结)
1.覆盖
有时希望子类继承基类的大部分行为,但是并不是所有行为。如果希望改变一个类继承的某些行为,可有覆盖(override)这些方法。
实现方法:
- 为基类中的方法增加virtual关键字。
子类智能覆盖标志有virtual关键字的方法,这就告诉C#允许子类覆盖这些方法。
//基类
class Bird
{
public virtual void Fly()
{
// code to make the bird fly
}
}
- 为派生类增加一个同名方法。
这个方法要有完全相同的方法签名,这说明返回值和参数都要相同而且声明中要使用override关键字。
//子类
class Penguin : Bird
{
public override void Fly()
{
MessageBox.Show("Penguin can't fly!")
}
}
2.向要求基类作为形参的函数传入子类
对于继承,最有用的一点就是可以使用子类来取代它继承的基类。但是函数只能访问形参中基类的成员,不能访问子类中特有的成员。
//基类
class Bird
{
public virtual void Fly()
{
// code to make the bird fly
}
}
//子类
class Penguin : Bird
{
public override void Fly()
{
MessageBox.Show("Penguin can't fly!")
}
}
internal class Program
{
private static void Main()
{
HuntBird(new Penguin);
Console.ReadKey();
}
private void HuntBird(Bird bird)
{
bird.Fly();
}
}
3. override和new的区别
二者的不同主要体现在,基类的引用变量指向子类实例对象时,即把子类的对象转化成基类类型。当变量调用被override或者new后的方法时,表现为如下不同:
- override的方法,会覆盖基类中的方法,用该变量调用这个方法时,总是调用子类中的方法;
- new的方法,会隐藏基类中的方法,用该变量调用这个方法时,总是调用基类中的方法。
代码示例:
//基类
class Bird
{
public virtual void Fly1()
{
Console.WriteLine("Bird Fly1");
}
public virtual void Fly2()
{
Console.WriteLine("Bird Fly2");
}
}
//子类
class Penguin : Bird
{
public override void Fly1()
{
Console.WriteLine("Penguin Fly1");
}
public new void Fly2()
{
Console.WriteLine("Penguin Fly2");
}
}
internal class Program
{
private static void Main()
{
Bird b1 = new Penguin();
b1.Fly1();//输出"Penguin Fly1"
b2.Fly2();//输出"Bird Fly2"
Console.ReadKey();
}
private void HuntBird(Bird bird)
{
bird.Fly();
}
}
备注:在建立类层次结构时,通常是覆盖方法而不是隐藏方法。如果确实是要隐藏方法,就要使用new关键字。
3. virtual和abstract的区别
- virtual修饰的方法必须要有实现(只有一对大括号也可以),abstract修饰的方法不能有实现;
- virtual修饰的方法在子类中可以重写也可以不重写,abstract修饰的方法在子类中必须要重写;
- 只有类被修饰为abstract,该类中的函数才能被修饰为abstract;
- abstract修饰的类不能实例化;
- 如果要重写基类中virtual修饰的方法,子类中的该方法要用override修饰。
4. 子类用base关键字访问其基类
计时子类覆盖了基类中的方法或属性,有时仍需要访问基类中的成员。使用base关键字可以访问基类中的任何方法。
using System;
namespace base关键字
{
internal class Program
{
private static void Main()
{
var child = new ClassChild();
child.F2();
Console.ReadKey();
}
}
//基类
internal class ClassBase
{
public virtual void F1()
{
Console.WriteLine("base F1");
}
}
//子类
internal class ClassChild : ClassBase
{
public override void F1()
{
Console.WriteLine("child F1");
}
public void F2()
{
base.F1();//调用基类函数
}
}
}
上面代码输出:
base F1
5. 基类中有构造函数,子类中也要有构造函数
如果基类中有构造函数(尤其是当有带参数的构造函数),继承这个类的所有子类必须调用其中一个构造函数。
using System;
namespace 子类构造函数
{
internal class Program
{
private static void Main()
{
var child= new ClassChild("正在调用子类的构造函数",11);
Console.ReadKey();
}
}
//基类
internal class ClassBase
{
public ClassBase(string information)
{
Console.WriteLine("base class constructor" + information);
}
}
//子类
internal class ClassChild : ClassBase
{
//调用子类的构造函数前先调用基类的构造函数
public ClassChild(string information, int number) : base(information)
{
Console.WriteLine("child class constructor" + information + number);
}
}
}
备注:子类实例化时先调用基类构造函数,再调用子类构造函数。