6

我试图理解 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();
        }
    }
}

我得到了相同的结果,即调用并打印了“派生方法”。我的问题是,如果代码在没有虚拟/覆盖的情况下像我预期的那样工作,它们有什么需要?还是我在这里遗漏了什么?

4

6 回答 6

12

在您的源代码中,您总是在进行简单的继承,而没有任何多态行为。您总是创建派生类的实例并将其分配给派生类实例变量。

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 关键字将绑定到正确版本的方法延迟到运行时,并且是实现多态性的核心关键。因此,对于精确的多态行为,在父类中将方法声明为 virtual,然后在子类中,覆盖该方法。

于 2013-07-16T13:36:41.070 回答
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,因为声明的类型bBase

于 2013-07-16T13:26:25.443 回答
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
}
于 2013-07-16T13:27:40.943 回答
2

看到不同

        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();
            }
        }

OUTPUT :
派生方法
派生方法

            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();
                }
            }

输出
派生方法
基本方法

于 2013-07-16T13:48:15.740 回答
2

基类指针可用于指向基类的对象或从基类派生的任何对象。所以当基类对象指向派生类时,就需要虚拟方法了

Base d = new Derived();
d.method(); // "Derived method"
于 2013-07-17T06:26:43.143 回答
0

派生类上的方法“方法”将隐藏基类的实现,这就是您收到消息“派生方法”的原因。

虚拟和抽象有很多用途,但一个例子是基类中的功能可能不适合从基类继承的所有类的情况。使用 virtual 允许另一个类完全覆盖该功能并提供自己的实现。

于 2013-07-16T13:27:03.190 回答