如何利用类的继承关系来构建类的层次结构呢?
继承的定义
继承用于定义”属于“关系,派生类是对基类的特化。
继承建立了“属于"has-a
的关系,派生类型总是隐式地属于基类型。
- 派生/继承 对基类进行特化,包含附加的成员或对基类成员进行自定义。
- 派生类型/子类型 继承常规类型的成员的特化类型
- 基/超/父类型 其成员由派生类型继承的常规类型
派生
继承设计的目的是为了扩展现有类型来扩充或添加更多的功能,包括数据与行为。通过继承,基类成员都会出现在派生类的链条中。除非明确指定基类,否则所有类都默认从object
类派生。
基类型和派生类型之间的转型
- 类的继承
- 类在功能上的扩展
- 只能有一个基类但可实现多个接口
- 类访问级别对继承的影响
-
sealed
类不能被继承
- 成员的继承与访问
- 派生类对继承成员的访问
- 派生类对基类成员的访问
- 构造器的不可继承性
- 面向对象的实现风格
- Class-based
- Prototype-based
子类父类
using System;
namespace Test
{ //基类: 交通工具类
class Vehicle
{}
//派生类: 私家车
class Car : Vehicle
{}
class Program
{
static void Main(string[] args)
{
//获取继承关系
Type type = typeof(Car);
Type basetype = type.BaseType;
Console.WriteLine(basetype.FullName);//Test.Vehicle
//.NET类型系统是单根的,所有类的基类是Object。
Type top = basetype.BaseType;
Console.WriteLine(top.FullName);//System.Object
//Object类是没有基类的
Console.WriteLine(top.BaseType==null);//True
//is-a “是一个”:一个派生类的实例从语义上来说也是一个基类的实例
Car car = new Car();
Console.WriteLine(car is Vehicle);//True
Console.WriteLine(car is Object);//True
Vehicle vehicle = new Vehicle();
Console.WriteLine(vehicle is Car);//False
//is-a: 使用一个父类的变量引用子类类型的实例
Vehicle v = new Car();
Console.ReadKey();
}
}
}
封闭类
using System;
namespace Test
{
//基类: 交通工具类
class Vehicle{}
//派生类: 私家车
class Car : Vehicle{}
//私用sealed修饰的类被视为一个封闭类,封闭类不能当作基类被继承。
sealed class Employee { }
/**
* 单继承:C#中一个类仅允许有一个基类
* 基类:实际上指继承自某个基类或派生自某个基类
* 基接口:一个C#类只能有一个积累,但可实现多个基接口。
* 基接口:某个类实现了某个基接口
* C++是多继承,即一个子类可继承多个父类。
*/
//class Toy : Vehicle, Employee{}
/**
* 子类的访问级别不能超越父类的访问级别
* internal 的访问级别是assembly程序集的
*/
//internal class User { }
//public class Member : User { }
class Program
{
static void Main(string[] args)
{
}
}
}
类成员
继承的本质是派生类在基类已有的成员的基础上进行横向和纵向的扩展
using System;
namespace Test
{
/**
* 继承链
*/
//基类
class Vehicle
{
public string Onwer { get; set; }
}
//派生类
class Car : Vehicle{}
//派生类
class RaceCar : Car { }
class Program
{
static void Main(string[] args)
{
RaceCar raceCar = new RaceCar();
raceCar.Onwer = "junchow";
//F12查看定义 Ctrl+[-] 返回
Console.WriteLine(raceCar.GetType());
Console.ReadKey();
}
}
}
从属性和行为上找到上面4种动物的相同点,如属性上的名字,行为上的叫唤。
首先,封装每个动物的名字和叫唤的行为。
using System;
namespace Test
{
class Dog
{
public string Name { get; set; }
public void Shout()
{
Console.WriteLine(this.Name+": dog shout");
}
}
class Cat
{
public string Name { get; set; }
public void Shout()
{
Console.WriteLine(this.Name+": cat shout");
}
}
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog() { Name = "alice" };
Console.ReadKey();
}
}
}
现在的问题是出现大量重复的代码,我们使用继承或派生来进行解决。
using System;
namespace Test
{
class Animal
{
public string Name { get; set; }
}
class Dog : Animal
{
public void Shout()
{
Console.WriteLine(this.Name + " : www...");
}
}
class Cat : Animal
{
public void Shout()
{
Console.WriteLine(this.Name + " : mmm...");
}
}
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog() { Name = "alice" };
Console.ReadKey();
}
}
}
继承的语意
-
is-a
是一个,表示属于的关系。
猫、狗都属于动物 -
has-a
有一个,表示拥有(包含)的关系。
动物拥有名字
单一继承 & 继承链
protected
和public
能在派生类中继承
例如:给动物添加一个隐私属性
using System;
namespace Test
{
//隐私数据
class SecretData
{
public int Age { get; set; }
}
//动物
class Animal
{
//public和protected能在派生类中继承
public string Name { get; set; }
//protected 受保护的,继承的子类可以访问。
protected SecretData SecretData = new SecretData();
}
//狗
class Dog : Animal
{
public void Shout()
{
Console.WriteLine("{0}: {1} wang,wang,wang...", this.Name, SecretData.Age);
}
}
//猫
class Cat : Animal
{
public void Shout()
{
Console.WriteLine("{0}: {1} miao,miao,miao...", this.Name, SecretData.Age);
}
}
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog() { Name = "alice" };
Console.ReadKey();
}
}
}
密封类sealed
,密封类表示无法被子类继承。
例如string
类是一个封闭的
基类base
的作用
- 访问基类的成员
- 访问基类的构造函数