方法隐藏是指通过重新实现来改变父类的方法在子类中的行为。
根据定义,我们所做的只是隐藏或隐藏或更好地“忽略”父类方法。
等一下!!这正是方法覆盖的内容。那么,如果它具有相同的目的,为什么我们甚至需要方法隐藏呢?这就是我们将在本文中回答的问题。
这是多态性系列的第 3 部分,我们将深入探讨多态性。以下是拼图的 3 个部分。
- 编译时多态性
- 运行时多态性
- 方法隐藏/阴影
注意:方法覆盖和方法隐藏的方法签名应该完全相同。
首先,我们将看到这两者之间的实现差异,然后我们将看到操作差异。
实现差异
- 在方法覆盖中,只允许在子类中覆盖虚拟或抽象方法,但在方法隐藏的情况下,子类可以重新实现父类的任何方法,无论是虚拟还是抽象。
- 关键字 override 用于被覆盖的方法,其中关键字 new 用于隐藏方法。
让我们一步一步来破解这个难题,让我们创建一个 Vehicle 类,它有一个虚拟方法 Speed() 和另一个普通方法 SetFuelType()。
public class Vehicle
{
public virtual string Speed()
{
return "Vehicle's speed is 10 Mph";
}
public string SetFuelType()
{
return "Vehicle runs on Diesel";
}
}
如果我现在使用父对象运行项目,我将得到以下输出。
让我们创建一个子类 Car 来重新实现这两个方法。
public class Car : Vehicle
{
//Method Override
public override string Speed()
{
return "Car's speed is 20 Mph";
}
//Method Hiding
public new string SetFuelType()
{
return "Car runs on Petrol";
}
}
现在看看会发生什么,当我用子类的对象调用这些方法时。
子对象调用自己重新实现的方法。
还有一点需要注意,关键字 new 是可选的,但如果你没有使用它,那么编译器会抛出一个警告。
警告:“Car.SetFuelType()”隐藏了继承的成员“Vehicle.SetFuelType()”。 如果打算隐藏,请使用 new 关键字。
现在,您可能会问覆盖和隐藏之间的具体区别是什么,因为我们看到它们在做完全相同的事情,但使用不同的方法。
操作差异
当我们尝试使用子类对象调用父类方法时,差异就出现了。
有两种方法可以在子类中引用父类。
1. 在子类中使用 base 关键字,查看清单 3 中的第 19 行和第 25 行。
public class Vehicle
{
public virtual string Speed()
{
return "Parent: Vehicle's speed is 10 Mph";
}
public string SetFuelType()
{
return "Parent: Vehicle runs on Diesel";
}
}
public class Car : Vehicle
{
//Method Override
public override string Speed()
{
return base.Speed();
}
//Method Hiding
public new string SetFuelType()
{
return base.SetFuelType();
}
}
在下图中,您可以看到子类汽车的实例如何调用其父类汽车的实现。
2. 第二种方式,这就是一切开始变得阴暗的地方。
您可以使用父类引用变量来存储子类对象。
像这样的东西。
Vehicle parent = new Car();
这个引用变量将可以访问所有属于父类的方法,但是在访问子类的成员时,它不能调用除被覆盖的方法之外的任何纯子类成员函数的方法。
public class Vehicle
{
public virtual string Speed()
{
return "Parent: Vehicle's speed is 10 Mph";
}
public string SetFuelType()
{
return "Parent: Vehicle runs on Diesel";
}
}
public class Car : Vehicle
{
//Method Override
public override string Speed()
{
return "Child: Car's speed is 20 Mph";
}
//Method Hiding
public new string SetFuelType()
{
return "Child: Car runs on Petrol";
}
}
您可以在清单 4 中看到,第 17 行的方法 Speed() 是 Car 类中的一个重写方法。 在图 4 中,父类 Vehicle 的引用变量正在调用子类 Car 的 Speed() 覆盖版本。 根据我们上面的规则,它按预期工作,“它不能调用任何子类的纯成员函数,除了被覆盖的方法。”
接下来要在清单 4 中观察,第 23 行的方法 SetFuelType() 是 Car 类中的隐藏方法。 在图 4 中,父类 Vehicle 的引用变量忽略了子类 Car 的实现并调用父类 Vehicle 的 SetFuelType() 版本。
注意:带有 new 关键字的方法被认为是纯成员函数,因为 new 关键字隐藏了父方法,现在它属于子方法。 在清单 5 中,我将第 17 行处的 Speed() 方法的关键字从 override 更改为 new。现在它将被视为 Car 类的纯定义方法。
public class Vehicle
{
public virtual string Speed()
{
return "Parent: Vehicle's speed is 10 Mph";
}
public string SetFuelType()
{
return "Parent: Vehicle runs on Diesel";
}
}
public class Car : Vehicle
{
//Method Hiding
public new string Speed()
{
return "Child: Car's speed is 20 Mph";
}
//Method Hiding
public new string SetFuelType()
{
return "Child: Car runs on Petrol";
}
}
结论
父类可以有虚方法或它自己的纯成员函数。 当父类在图 4 中的子类中进行类型转换时,
在 Overriding 中,它跳过了虚拟方法并调用了子类覆盖的方法,这就是为什么在图 4 中调用了 child 的 speed() 方法。
在方法隐藏的情况下,它首先在自身中查找纯成员函数,如果找到则跳过带有 new 关键字的子类隐藏方法,这就是为什么在图 4 中调用了父类的 SetFuelType() 方法。
注意:如果虚方法没有任何被覆盖的方法,那么如果没有找到被覆盖的实例,父类将调用它自己的方法。
免责声明: 文章源于会员发布,不作为任何投资建议
如有侵权请联系我们删除,本文链接:https://www.sws100.com/baike/381087.html