我正在尝试理解C#中覆盖和虚拟的需要,所以我编写了以下代码:
using System;
namespace Override
{
class Base
{
public virtual void method()
{
Console.WriteLine("Base method");
}
}
class Derived : Base
{
public override void method()
{
Console.WriteLine("Derived method");
}
}
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
d.method();
}
}
}
我期待调用并打印“派生方法”。然后我在不使用虚拟/覆盖组合的情况下编写了以下代码。
using System;
namespace Override
{
class Base
{
public void method()
{
Console.WriteLine("Base method");
}
}
class Derived : Base
{
public void method()
{
Console.WriteLine("Derived method");
}
}
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
d.method();
}
}
}
我得到了相同的结果,即“派生方法”被调用和打印。我的问题是,如果代码在没有虚拟/覆盖的情况下工作,我预期,他们需要什么?或者我在这里遗漏了什么?
答案 0 :(得分:11)
在源代码中,您总是在进行简单继承而没有任何多态行为。始终创建派生类的实例并将其分配给派生类实例变量。
DerivedClass d = new DerivedClass(); // here no polymorphism, and only inheritance is there
因此,当您使用类变量调用方法时,无论该方法在父类中是否为虚方法,它都将始终调用DerivedClass方法。
在多态性中,您的程序不知道您调用该方法的类的确切类型(此概念称为后期绑定)。如下例所示:
BaseClass b = new DerivedClass(); // here b is a base class instance but initiated using derived class
在调用b.method()之后,它将进行后期绑定并显示多态行为(仅当该方法已在基类中设置为虚拟时)
注意:virtual关键字将绑定到正确的方法版本延迟到运行时,并且是实现多态的核心关键。因此,对于确切的多态行为,在父类中将方法声明为虚拟,然后在子类中,将该方法设为ovverride。
答案 1 :(得分:8)
virtual
允许在运行时根据编译时不可用的信息选择正确的方法版本。请考虑以下对您示例的调整:
using System;
namespace Override
{
class Base
{
public virtual void method()
{
Console.WriteLine("Base method");
}
}
class Derived : Base
{
public override void method()
{
Console.WriteLine("Derived method");
}
}
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
Base b = d;
b.method();
}
}
}
使用virtual
/ override
,此代码将显示Derived method
,因为在运行时我们可以看到b
实际上是Derived
实例。如果没有virtual
/ override
,则会显示Base method
,因为b
的声明类型为Base
。
答案 2 :(得分:3)
以下是您缺少的测试:
Base d = new Derived();
d.method(); // "Derived method"
Base b = new Base();
b.method(); // "Base method"
还要想象一下,如果你有一组由不同的继承对象组成的Base
个对象。 virtual
关键字允许那些Base
对象了解它们在运行时的实际类型。
List<Base> collection = new List<Base>();
collection.Add(new Base());
collection.Add(new Derived()};
collection.Add(new Base());
foreach(Base b in collection)
{
b.method(); // will print out "Base" or "Derived" correctly
}
答案 3 :(得分:2)
参见DIFFERENCE
class Base
{
public void method()
{
Console.WriteLine("Base method");
}
}
class Derived : Base
{
public void method()
{
Console.WriteLine("Derived method");
}
}
class Program
{
static void Main(string[] args)
{
Derived d;
d = new Derived();
d.method();
d = new Base();
d.method();
}
}
输出:
派生方法
派生方法
class Base
{
public virtual void method()
{
Console.WriteLine("Base method");
}
}
class Derived : Base
{
public override void method()
{
Console.WriteLine("Derived method");
}
}
class Program
{
static void Main(string[] args)
{
Derived d;
d = new Derived();
d.method();
d = new Base();
d.method();
}
}
输出:
派生方法
基本方法
答案 4 :(得分:2)
基类指针可用于指向基类的对象或从基类派生的任何对象。因此,当基类对象指向派生类
时,需要虚拟方法Base d = new Derived();
d.method(); // "Derived method"
答案 5 :(得分:0)
Derived类的方法'method'将隐藏Base类的实现,这就是你得到消息“Derived method”的原因。
虚拟和抽象有很多用途,但是一个例子是你在基类中有功能,它可能不适合从你的基类继承的所有类的情况。使用virtual允许另一个类完全覆盖该功能并提供自己的实现。