3

如果我有这样的事情:

class Base
{
    public void Write()
    {
     if (this is Derived)
      {
         this.Name();//calls Name Method of Base class i.e. prints Base
        ((Derived)this).Name();//calls Derived Method i.e prints Derived 
      }
     else
      {
        this.Name();
      }
    }

    public void Name()
    {
        return "Base";
    }
}

class Derived : Base
{
    public new void Name()
    {
        return "Derived";
    }
}

并使用以下代码调用它,

Derived v= new Derived();
v.Write(); // prints Base

然后Name调用基类的方法。this但是该方法中关键字的实际类型是Write什么?如果那是Derived类型(当程序控件进入Write方法中的第一个 if 块时),那么它正在调用基Name方法,为什么显式转换(Derived)this,改变对Name派生类方法的调用?

4

4 回答 4

7

this将始终是派生类类型。

在调用中this.Name();调用基类Name()方法的原因是因为没有定义为虚拟方法,因此当编译器对此时它将具有Name的实际类型一无所知时,它在编译时被链接。this

关于上面代码的另一个注意事项。通常,在产品代码中明确地从基类引用派生类确实是一种不好的做法,因为它违反了基类不应该知道继承它的类的 OOP 原则之一。但是,假设上面的代码只是用于 C++ 调查,那么这当然没问题。

于 2015-04-24T22:05:30.657 回答
2

如果要访问派生类中的任何重写成员,则应该使用 virtual 和 override:

class Base
{
    public void Write()
    {
     if (this is Derived)
      {
         this.Name();//calls Name Method of Base class i.e. prints Base
        ((Derived)this).Name();//calls Derived Method i.e prints Derived 
      }
     else
      {
        this.Name();
      }
    }

    public virtual void Name()
    {
        return "Base";
    }
}

class Derived : Base
{
    public override void Name()
    {
        return "Derived";
    }
}
于 2015-04-24T22:05:32.263 回答
1

这就是你所需要的。您不需要也不应该从基础检查类型来处理逻辑。任何特殊逻辑都应在派生类中处理,并且可能希望将方法标记为virtual基类和override派生类中的方法。

class Base
{
    public void Write()
    {
        SomeWriteMethod(Name());
    }

    public virtual void Name()
    {
        return "Base";
    }
}

class Derived : Base
{
    public override void Name()
    {
        return "Derived";
    }
}

如果你想要类的实际名称Name(),你只需要调用GetType().Name基类,它会自动为任何派生类工作,因为它会GetType()返回实例的实际实例类型。就像GetType()实际实例一样,this也是您的实际实例,因此任何特殊逻辑都将属于该类的实现。

this实际上是您的基类中的冗余调用。要么你指定它,要么你不指定它——你会得到相同的结果。您看到混合结果的原因是您使用了new运算符。new仅当您使用该显式类型时才有效。它基本上隐藏了链中的其他实现。因此,this在上下文中Base将给你的Base.Name()where 就好像你已经被覆盖一样,Derived.Name()会被使用。

MSDN:知道何时使用覆盖和新关键字

这是一个很好的答案new——为什么在我的派生类中调用方法调用基类方法?

于 2015-04-24T22:13:22.790 回答
0

通过强制转换((Derived)this).Name(),您可以将其显式设置为派生类。由于您已Write在基类中定义,这将指向它的方法调用。出现此行为是因为您没有重写基方法并且您从基类调用它。

于 2015-04-24T22:09:25.307 回答