为什么抽象方法需要new / override,虚拟方法不需要?
样本1:
abstract class ShapesClass
{
abstract public int Area(); // abstract!
}
class Square : ShapesClass
{
int x, y;
public int Area() // Error: missing 'override' or 'new'
{
return x * y;
}
}
编译器将显示以下错误: 要使当前成员覆盖该实现,请添加override关键字。否则添加新关键字
样本2:
class ShapesClass
{
virtual public int Area() { return 0; } // it is virtual now!
}
class Square : ShapesClass
{
int x, y;
public int Area() // no explicit 'override' or 'new' required
{
return x * y;
}
}
通过默认隐藏方法,这将编译正常。
我完全理解技术差异。但我想知道为什么语言是这样设计的。 “样本2”中的限制也不是更好吗?我的意思是在大多数情况下,如果你创建一个与父类同名的方法,你通常打算覆盖它。所以我认为明确说明Override / New对虚拟方法也有意义。
这种行为是否存在设计明智的原因?
更新 第二个样本实际上会引发警告。第一个示例显示错误,因为子类是实现抽象方法所必需的。我没有看到VS中的警告..现在对我来说非常有意义。感谢。
答案 0 :(得分:11)
使用.NET 3.5 SP1中附带的C#3.0编译器或.NET 4.0中附带的C#4.0编译器,我得到以下错误作为您的第一个示例:
错误CS0534:'ConsoleApplication3.Square'未实现继承的抽象成员'ConsoleApplication3.ShapesClass.Area()'
以下警告第二个:
警告CS0114:'ConsoleApplication3.Square.Area()'隐藏继承的成员'ConsoleApplication3.ShapesClass.Area()'。要使当前成员覆盖该实现,请添加override关键字。否则添加新关键字。
在第一种情况下,这是一个错误,因为您实际上没有覆盖基本方法,这意味着在具体类中没有实现抽象方法。在第二种情况下,它是一个警告,因为代码在技术上是正确的,但编译器怀疑它不是你的意思。这是启用“将警告视为错误”编译设置通常是个好主意的原因之一。
所以我不能重复你的行为,编译器的行为对我来说是正确的。您使用的是哪个版本的编译器?
答案 1 :(得分:7)
以下是直接来自C#规范的答案。
...隐藏一个可访问的名称 继承范围会导致警告 报道。在示例中
class Base
{
public void F() {}
}
class Derived: Base
{
public void F() {} // Warning, hiding an inherited name
}
衍生原因中的F声明 要报告的警告。隐藏一个 继承的名称特别不是 错误,因为那样会排除 基类的单独演变。 例如,上述情况可能会发生 因为后来才出现 Base的版本引入了F方法 这在早先没有出现过 该类的版本。有上述 情况是一个错误,然后任何 改变了对基类的改变 单独版本的类库 可能导致派生 类变为无效。警告 隐藏继承名称所造成的 通过使用新的消除 改性剂:
class Base
{
public void F() {}
}
class Derived: Base
{
new public void F() {}
}
新修饰符表示F 在Derived中是“新的”,它就是 确实打算隐藏继承 构件。
答案 2 :(得分:3)
不同之处在于必须重写抽象方法,但虚拟不会。
在没有实现所有抽象成员的情况下继承抽象类(在非抽象类中)是一个错误,但是在从类继承而没有指定override
或new
时只会收到警告虚方法。
答案 3 :(得分:0)
我认为在第一种方式中你会遇到编译器错误,因为抽象方法是隐藏的而不是实现的(所以有效的你的类是错误的,并且很难找出原因)。在第二种情况下,您只得到一个警告,因为该类是可用的。
答案 4 :(得分:0)
乍一看,您可能认为隐藏方法看起来并不特别有用。有一种情况
但是,您可能需要使用它。假设您要使用名为MotorVehicle
的类
是由另一个程序员编写的,你想使用这个类来派生自己的类。进一步,
我们还假设您要在派生类中定义Accelerate()
方法。例如:
public class Car : MotorVehicle
{
// define the Accelerate() method
public void Accelerate()
{
Console.WriteLine(“In Car Accelerate() method”);
Console.WriteLine(model + “ accelerating”);
}
}
接下来,让我们假设其他程序员稍后修改MotorVehicle类并决定
添加自己的virtual Accelerate()
方法:
public class MotorVehicle
{
// define the Accelerate() method
public virtual void Accelerate()
{
Console.WriteLine(“In MotorVehicle Accelerate() method”);
Console.WriteLine(model + “ accelerating”);
}
}
其他程序员添加此Accelerate()
方法会导致出现问题:
Accelerate()
类中的Car
方法隐藏了现在定义的继承Accelerate()
方法
他们的MotorVehicle
课程。稍后,当您编译Car
类时,编译器不清楚
你是否真的希望你的方法隐藏继承的方法。因此,
当您尝试编译Car类时,编译器会报告以下警告:
警告CS0114:'Car.Accelerate()'隐藏继承的成员 “MotorVehicle.Accelerate()”。使当前成员覆盖该成员 实现,添加override关键字。否则添加新关键字。