继承
继承可以促进代码重用。
代码重用归为两类:经典继承(“is-a”)、包含/委托继承(”has-a”)
经典继承
// 经典继承使用“:”标记继承关系
// 继承类拥有父类每个公共成员的访问权限
class car
{}
class miniCar : car
{}
- .NET平台不允许类的多重继承(C/C++支持)
// 错误!不允许类的多重继承
class WontWork:BaseClassOne, BaseClassTwo
{}
- 可以使用 sealed 关键字来防止发生继承
sealed class minCar:Car
{}
// 错误,不能派生
class deluxeMinCar:minCar
{}
- 使用 base 关键字控制基类创建
class Employee
{
//字段数据
private string empName;
private int empID;
private float currPay;
private int empAge;
//自动属性
public string Name{get; set;}
public int Age{get; set;}
public int ID{get; set;}
public float Pay{get; set;}
//构造函数
public Employee(string name, int age, int id, float pay)
{
Name = name;
Age = age;
ID = id;
Pay = pay;
}
}
class Manager:Employee
{
public int StockOptions{get; set;}
//拥有6个输入的构造函数
public Manager(string fullName, int age, int empID, float currPay, \
string ssn, int numbOfOpts)
{
// 如果在这里初始化所有变量会有两个问题
// 1. 基类 Employee 非 public 的变量无法赋值
// 2. 非常低效,因为默认会先调用基类构造函数,然后再重复访问赋值
}
//使用 base
//有点像参数列表,先初始化基类构造函数
public Manager(string fullName, int age, int empID, float currPay, \
string ssn, int numbOfOpts):base(fullName, age, empID, currPay, ssn)
{}
}
包含/委托继承
简单来说,就是一个类包含另一个类
// 包含/委托
class Employee
{
// 包含一个 BenefitPackage 类的对象
protected BenefitPackage empBenfits = new BenefitPackage();
// 创建方法来使用其内部功能
public double GetBenefiCost()
{}
// 通过自定义属性公开对象
public BenefitPackage Benefits
{
get{return empBenfits;}
set{empBenfits = value;}
}
}
还有一种包含/委托的方式:嵌套类型
// 嵌套类型
public class OuterClass
{
// 公共嵌套类型
public class PublicInnerClass{}
// 私有嵌套类型
private class PrivateInnerClass{}
}
- 嵌套类型可以完全控制内部类型的访问级别(非嵌套类型不能用 private,protected)
- 由于嵌套类型是包含类(OuterClass)的成员,因此可以访问包含类私有成员
多态
简单说,就是子类对父类的方法重写
虚函数 virtual
// 多态
class Shape
{
// 使用 virtual 定义一个虚方法
public virtual void Draw()
{
Console.WriteLine("Inside Shape.Draw()");
}
}
class Circle:Shape
{
// 子类可以不实现父类的虚函数
// 其对象直接调用父类虚函数
}
class Hexagon:Shape
{
// 子类使用 override 重写虚方法
public override void Draw()
{
Console.WriteLine("Drawing the Hexagon");
}
}
抽象类 abstract
// 抽象类
// 抽象类里才可以定义抽象方法
abstract class Shape
{
// 与虚方法的不同是,抽象方法没有具体实现
// 但规定所有子类必须实现该函数
public abstract void Draw();
}
class Circle:Shape
{
// 子类使用 override 重写抽象方法
public override void Draw()
{
Console.WriteLine("Drawing the Circle");
}
}
成员投影
有时候对第三方父类做派生,需要重写函数,但父类相应的函数没有定义为虚函数或抽象函数
可以用 new 关键字隐藏父类版本
// 成员投影
// 父类
class Circle
{
public void Draw()
{
Console.WriteLine("Drawing a Circle");
}
}
// 派生类,需要重写Draw
class ThreeCircle:Circle
{
public new void Draw()
{
Console.WriteLine("Drawing a 3D Circle");
}
}
// 调用 ThreeCircle 的 Draw()
ThreeCircle o = new ThreeCircle();
o.Draw();
// 也可以使用显式强制转换调用基类实现
((Circle)o).Draw();
基类与派生类的转换
- 派生类可以隐式转换为父类
// 派生类 -> 父类
// 所有东西都是 object 的派生类
object frank = new Manager();
- 父类可以显示转换为派生类
// 父类 -> 派生类
(Manager)frank
- 使用“is”或“as”判断转换是不是有效
// 使用 is 关键字判断是不是指定的派生类
if(frank is Manager)
{...}
// 使用 as 关键字判断转换是不是有效
Manager man = frank as Manager;
if(man == null)
Console.WriteLine("frank is not a Manager");
参考
【1】C#与.NET 4高级程序设计(第5版)