第26节 重写(纵向扩展)、多态
类的继承
- 类成员的“横向扩展”(成员越来越多)
- 类成员的“纵向扩展”(行为改变,版本增高)
- 类成员的隐藏(不常用)
- 重写与隐藏的发生条件:函数成员,可见(由父类继承下来的函数成员,对子类是可见的),签名一致
如果父类成员用protected修饰,则子类可以继承,但是不能访问该成员
Java 天然重写,不需要修饰符
举例:
(1)方法重写:
要求父类成员用 virtual 修饰,子类成员用 override 修饰
using System;
namespace OverrideExample
{
class Program
{
static void Main(string[] args)
{
Vehicle v = new Car();
v.Run();
}
}
//实现子类成员对父类成员的重写
//要求父类成员用 virtual 修饰,子类成员用 override 修饰
//如果父类成员和子类成员均没有修饰符,
//则称为子类成员对父类成员的隐藏
class Vehicle
{
public virtual void Run()
{
Console.WriteLine("I'm running.");
}
}
class Car : Vehicle
{
//子类对父类成员的重写(成员的纵向扩展)
public override void Run()
{
Console.WriteLine("Car is running.");
}
}
}
(2)属性成员重写
class Vehicle
{
private int _speed;
//Speed 属性
public virtual int Speed
{
get { return _speed; }
set { _speed = value; }
}
}
class Car : Vehicle
{
private int _rpm;
//Speed 属性重写
public override int Speed
{
get { return _rpm / 100; }
set { _rpm = value / 100; }
}
}
(3)隐藏
没有 virtual 和 override 修饰
注意重写和隐藏的区别!!!
多态(polymorphism)
- 基于重写机制(virtual -> override)
多态的本质: 当调用被重写成员时,能调到的永远是继承链上最新的,与实例类型相关的版本
举例:
(1)C#
例1:
using System;
namespace OverrideExample
{
class Program
{
static void Main(string[] args)
{
//Vehicle类型的变量
//在调用Run方法时,是一级一级往下,找到最新版本的Run
Vehicle v = new RaseCar();
v.Run();
}
}
//实现子类成员对父类成员的重写
//要求父类成员用 virtual 修饰,子类成员用 override 修饰
//如果父类成员和子类成员均没有修饰符,
//则称为子类成员对父类成员的隐藏
class Vehicle
{
public virtual void Run()
{
Console.WriteLine("I'm running.");
}
}
class Car : Vehicle
{
//子类对父类成员的重写(成员的纵向扩展)
public override void Run()
{
Console.WriteLine("Car is running.");
}
}
class RaseCar : Car
{
public override void Run()
{
Console.WriteLine("RaseCar is running.");
}
}
}
例2:与上一个例子的区别在于,RaseCar.Run() 方法没有写 override 修饰符
using System;
namespace OverrideExample
{
class Program
{
static void Main(string[] args)
{
//Vehicle类型的变量
//在调用Run方法时,是一级一级往下,找到最新版本的Run
Vehicle v = new RaseCar();
v.Run();
}
}
//实现子类成员对父类成员的重写
//要求父类成员用 virtual 修饰,子类成员用 override 修饰
//如果父类成员和子类成员均没有修饰符,
//则称为子类成员对父类成员的隐藏
class Vehicle
{
public virtual void Run()
{
Console.WriteLine("I'm running.");
}
}
class Car : Vehicle
{
//子类对父类成员的重写(成员的纵向扩展)
public override void Run()
{
Console.WriteLine("Car is running.");
}
}
class RaseCar : Car
{
public void Run()
{
Console.WriteLine("RaseCar is running.");
}
}
}
Vehicle 定义的变量 v ,自上而下,寻找最新版本的Run()
(2)Python 里面不存在多态
# Python 的变量是没有类型的,变量的类型与对象的类型一致
# 因此,Python 里面不存在多态
class Vehicle:
def run(self):
print("I'm running!")
class Car(Vehicle):
def run(self):
print("Car is running!")
class RaseCar(Car):
def run(self):
print("Rase car is running!")
v = Vehicle()
v = RaseCar()
v.run()
- 函数成员的具体行为(版本)由对象决定
- 回顾:C# 语言的变量和对象都是有类型的,所以会有“代差”
补充:
1)访问修饰符
(1)public :同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。
(2)private :只有同一类或结构中的代码可以访问该类型或成员。
(3)protected :只有同一类或结构或者此类的派生类中的代码才可以访问的类型或成员。
(4)internal :同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。
2)程序集
常见的两种程序集,可执行文件(.exe文件)和 类库文件(.dll文件)。在VS开发环境中,一个解决方案可以包含多个项目,而每个项目就是一个程序集。