如果我有这样的话:
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
类型(因为Program控件进入Write
方法中的第一个if块),那么它正在调用基本Name
方法,为什么显式转换,{{ 1}},将调用更改为派生类的(Derived)this
方法?
答案 0 :(得分:5)
this
将始终属于派生类类型。
调用this.Name();
中调用基类Name()
方法的原因是因为Name
未定义为虚方法,因此在编译时将其链接到编译时对此时所拥有的this
的实际类型一无所知。
关于上述代码的另外一个注释。通常在产品代码中明确引用Base类中的Derived类实际上是一种不好的做法,因为它破坏了Base类不应该知道继承它的类的OOP原则之一。但是,假设上面的代码仅用于C ++调查,那么这当然可以。
答案 1 :(得分: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";
}
}
答案 2 :(得分: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()
好像被覆盖一样,Derived.Name()
会被使用。
MSDN: Knowing when to use override and new keywords
以下是关于new
- Why does calling a method in my derived class call the base class method?
答案 3 :(得分:0)
通过转换((Derived)this).Name()
,您将显式设置为派生类。由于您在基类中定义了Write
,因此将指向对它的方法调用。出现此问题的原因是您没有重写基本方法,而是从基类调用它。