C#中的函数重写

7

我只是试图通过控制台应用程序来掌握虚函数的概念。我注意到,一旦我覆盖了基类函数,return baseclassname.functionname(parameters) 会自动插入到我的函数体中。为什么会这样呢?

class advanc
{
    public virtual int  calc (int a , int b)
    {        
         return (a * b);        
    }        
}

class advn : advanc
{
     public override int calc(int a, int b)
     {
          //automatically inserted
          return base.calc(a, b);
      }        
}
7个回答

12

通过重载虚函数,您可以扩展基类的功能,然后调用基类以执行“基本功能”。

如果您删除“return base.calc(a,b)”行,则不会执行基类代码。

如果您想完全替换功能,则没有问题,但如果您想扩展功能,则还应调用基类。

以下代码演示了这一点(只需将其放入控制台应用程序中即可)

class advanc
{
    public virtual int calc(int a, int b)
    {
        Console.WriteLine("Base function called");
        return (a * b);
    }
}

class advn : advanc
{
    public bool CallBase { get; set; }
    public override int calc(int a, int b)
    {
        Console.WriteLine("Override function called");

        if (CallBase)
        {
            return base.calc(a, b);
        }
        else
        {
            return a / b;
        }
    }
}

private static void Main()
{
    advn a = new advn();

    a.CallBase = true;
    int result = a.calc(10, 2);
    Console.WriteLine(result);

    a.CallBase = false;
    result = a.calc(10, 2);
    Console.WriteLine(result);
    Console.WriteLine("Ready");
    Console.ReadKey();
}

请问能否解释一下什么是get和set?我没有找到很好的例子。这是一种初始化变量的方式吗? - Karthik
1
{get; set;} 是自动实现属性。属性使用 get 和 set 来封装字段,以便不能直接读取或修改该字段。这是良好的编程实践。如果您想了解更多信息,可以访问 http://msdn.microsoft.com/en-us/library/bb384054.aspx。 - Wouter de Kort
这句话:“如果你删除'return base.calc(a,b)'这一行,基类代码将不会执行。”完全是胡说八道。是的,你可以删除那一行并编写任何想要覆盖基类虚函数的内容。这与基类代码无关。 - LearningMath

5

Visual Studio试图猜测您想要什么,因此建议您使用此代码。

有时,重写的函数扩展基类函数的功能。在这种情况下,在重写的函数中的某个位置调用base.function是可行的。


2
IDE试图生成最简单的重写方法,以使其能编译通过(如果您将实际实现留给以后,仍然有一段代码,虽然没有做太多事情但是仍然能编译通过并产生一个结果,这个结果可能不会破坏您代码中的其他部分)。
此外,还有一些场景,在实现后调用基类方法仍然是有意义的:
  1. 您的子类行为扩展了基类但并未完全替换它
  2. 您正在使用装饰器模式,但calc方法不需要更改(您仍然需要实现它,因为它是您要装饰的原始接口的一部分,但是您只需将调用转发到基类而不更改行为)

2
这意味着当调用base.calc时,它将调用被覆盖的父函数。如果您不想调用基本函数,则可以删除它,但在大多数情况下,它将保留(这就是为什么Visual Studio自动生成它的原因)。
如果在您的高级函数中不想调用a * b功能,则可以删除base函数调用并编写自己的代码。
例如,如果您在advn类中声明了以下内容:
public override int calc(int a, int b)
{
   return Math.Pow(a, b);
}

调用此功能时,您将获得以下内容:
advanc myObj = new advanc();
advn advnObj = new advn();

myObj.calc(5, 2); // will return 10
advnObj.calc(5, 2); // will return 25

1
我本来会更早完成编辑的,但是我听到了外面食品车的声音! - Lloyd Powell

1

IDE 只是简单地插入了对基本实现的调用。这意味着,默认情况下,重写的行为将与其覆盖的方法相同。如果这不是所需的行为(很可能不是),只需使用您选择的代码进行替换即可。


1

默认情况下,VS至少提供在函数中执行与父级相同的操作。此外,在许多情况下,您需要先运行父级,然后执行您的操作(例如,在UI案例中)。有关base请参阅MSDN:

The base keyword is used to access members of the base class from within a derived class:

Call a method on the base class that has been overridden by another method.
Specify which base-class constructor should be called when creating instances 
of the derived class.

A base class access is permitted only in a constructor, an instance method, or an instance property accessor.


1

基础函数体会因为这行代码 return base.calc(a, b); 被自动调用。但是,你可以简单地让基础函数体不被自动调用,而像这样调用你自己的函数:

    class advn : advanc
    {
        public override int calc(int a, int b)
        {
             return a * b; //anything else;
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接