如果我有以下基类:
class A
{
public virtual void print()
{
Console.WriteLine("Base class method");
Console.Read();
}
}
从下面继承自基类的派生类:
class B : A
{
public override void print()
{
Console.WriteLine("Child Class Method");
Console.Read();
}
}
创建对象的主要方法如下:
class Method
{
static void Main(string[] args)
{
A obj=new B();
obj.Print();
}
}
上面的代码将调用子类方法。但即使我创建了像B obj=new B()
这样的对象并执行了'obj.Print()',也会呈现相同的输出。
那么创建像A obj=new B()
之类的对象和调用上面的方法有什么用?
另一方面,如果我改变派生类方法如下:
public new void print()
{
Console.WriteLine("Child Class Method");
Console.Read();
}
如果A obj=new B()
,那么obj.print()
将调用基类方法。如果我执行A obj=new A()
和obj.print()
,则相同。
那么有一个基类引用变量指向派生的引用类对象并调用上面的成员有什么意义呢?在哪种情况下应该使用这种逻辑?
答案 0 :(得分:1)
你有一个带有这个签名的方法:
void Print(ICollection<A> objects)
{
foreach(var obj in objects)
{
obj.print();
}
}
print
将使用B
实施或A
实施(对于A
,可能是另一个C
未new
的{{1}} print
方法)
阅读:https://stackoverflow.com/a/6162547/6460438
答案 1 :(得分:0)
你这样做的原因是多态性。例如,您可能有一个方法:
void Process(A item)
{
item.print();
}
现在你可以说:
B b = new b();
Process(b);
虽然该方法需要A
,但它会调度到正确的实现。
答案 2 :(得分:0)
这里的指导原则是,当您处理对象时,您应该使用符合您需求的最广泛类型(至少 - 来源类型)。这有时表示为&#34;代码到接口,而不是实现。&#34;不过,不要对这个术语感到困惑。对基类进行编码也很好,如果这是满足您需求的类型。
原因很简单:它简化了以后的维护和重构,并使代码更容易在其他地方重用。变量的类型对该变量的工作方式做出承诺。如果您将这些承诺变得更广泛,那么让您的功能更广泛适用变得更容易。当您为变量类型选择基类时,您可以对以后更改底层实现更有信心。
在您的示例中,如果我针对A
进行编码,但创建了B
的实例,那么我可以非常自信地在以后添加class C : A { ... }
时可以使用它在这个功能,如果我想。如果我直接对B
进行编码,则难以证明。
关于这些关键字与此相关的方式:
virtual
用于将方法标记为子类可以重新定义的方法(实际上,我们可能期望子类重新定义它,至少偶尔会重新定义它)。如果有一个合理的默认实现可以在大多数情况下工作,你可以使用它,但仍然希望为子类提供一种方法来潜在地优化函数以供自己使用。
abstract
用于表示此类要求子类为&#34;填写&#34;一些遗漏的细节。当你无法知道如何实现方法时使用它,但是你知道你需要这个方法。 abstract
方法始终为virtual
。如果class
定义了任何abstract
方法,则类本身必须为abstract
,并且您无法实际创建它的实例。根据我自己的经验,我使用的abstract
超过virtual
。
override
用于表示此类实际(重新)定义父类的行为。
new
有点特殊。由于父类必须明确授予其子类的权限以重新定义方法,因此我们不能在任何我们想要的地方override
。这通常是好的事情,但有时候,你需要超越规则。 (那个混蛋图书馆的作者&#34;忘了&#34;制作一个方法virtual
,我们需要进行一项重大的优化......)new
是什么{{1}} 。如果它们妨碍了它,它为我们提供了一种绕过正常继承规则的方法。你应该谨慎使用这个非常。