C# 创建“派生类”类型的对象
我最近一直在研究类继承,我不断遇到这段特定的代码C# 创建“派生类”类型的对象,c#,inheritance,derived-class,C#,Inheritance,Derived Class,我最近一直在研究类继承,我不断遇到这段特定的代码 public class Foo { public bool DoSomething() { return false; } } public class Bar : Foo { public new bool DoSomething() { return true; } } public cass Test { public static void Main ()
public class Foo {
public bool DoSomething()
{
return false;
}
}
public class Bar : Foo {
public new bool DoSomething()
{
return true;
}
}
public cass Test {
public static void Main () {
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
这里让我困惑的是,如果是我,我会按类型Bar创建一个Bar实例
Bar test = new Bar();
我不明白为什么会按照代码中的方式创建它。通常不会。一个更现实的例子是
void DoSomethingWithAFoo(Foo f) {
f.DoSomething();
}
在这种情况下,f可以是一个Foo或一个Bar,DoSomethingWithAFoo不需要知道或关心。一般来说,它不会。一个更现实的例子是
void DoSomethingWithAFoo(Foo f) {
f.DoSomething();
}
在这种情况下,f可以是一个Foo或一个Bar,DoSomethingWithAFoo不需要知道或关心。Bar源于Foo,因此创建一个Bar实例并分配给一个Foo引用是完全有效的。我怀疑您所展示的示例代码仅仅表明Bar是一个Foo,因此是可赋值的。Bar源于Foo,因此创建Bar实例并将其赋值给Foo引用是完全有效的。我怀疑您所展示的示例代码仅仅表明Bar是一个Foo,因此是可赋值的。在现实世界的对象中更容易想到这些东西 试着想想一辆车。您可以拥有不同品牌/型号的汽车,但每辆汽车的基本功能相同 您的代码可以以同样的方式处理对象。您编写的代码适用于任何汽车,但您确实可以指定您想要的任何品牌/型号的汽车:
public class Car
{
public virtual void Drive()
{
}
}
public class ChevyVolt : Car
{
public override void Drive()
{
// Initialize the battery and go
}
}
public class CadillacEscalade : Car
{
public override void Drive()
{
// Check to ensure you have an oil field worth of gas and go
}
}
现在,使用这些定义…您可以创建一个负责驾驶汽车的类。什么车都行。你只需要担心驾驶:
public class Commuter
{
public void GoToWork()
{
// Garage.PickCar() could return either ChevyVolt or an Escalade
Car todaysRide = Garage.PickCar();
// Now that we have a car, go to work
todaysRide.Drive();
}
}
在现实世界的对象中更容易想到这些东西 试着想想一辆车。您可以拥有不同品牌/型号的汽车,但每辆汽车的基本功能相同 您的代码可以以同样的方式处理对象。您编写的代码适用于任何汽车,但您确实可以指定您想要的任何品牌/型号的汽车:
public class Car
{
public virtual void Drive()
{
}
}
public class ChevyVolt : Car
{
public override void Drive()
{
// Initialize the battery and go
}
}
public class CadillacEscalade : Car
{
public override void Drive()
{
// Check to ensure you have an oil field worth of gas and go
}
}
现在,使用这些定义…您可以创建一个负责驾驶汽车的类。什么车都行。你只需要担心驾驶:
public class Commuter
{
public void GoToWork()
{
// Garage.PickCar() could return either ChevyVolt or an Escalade
Car todaysRide = Garage.PickCar();
// Now that we have a car, go to work
todaysRide.Drive();
}
}
编写此代码可能是为了演示重写和隐藏基类方法之间的区别: 在这种情况下,使用Foo变量实例化Bar对象将使用基类方法DoSomething并输出false。如果DoSomething方法在基类中声明为virtual,并在派生类中重写,则输出将为true,如下例所示:
public class Foo {
public virtual bool DoSomething()
{
return false;
}
}
public class Bar : Foo {
public override bool DoSomething()
{
return true;
}
}
编写此代码可能是为了演示重写和隐藏基类方法之间的区别: 在这种情况下,使用Foo变量实例化Bar对象将使用基类方法DoSomething并输出false。如果DoSomething方法在基类中声明为virtual,并在派生类中重写,则输出将为true,如下例所示:
public class Foo {
public virtual bool DoSomething()
{
return false;
}
}
public class Bar : Foo {
public override bool DoSomething()
{
return true;
}
}
您可以分配一个更通用的Foo和一个不太通用的Boo类型,这通常是在利用多态性时完成的。经典的例子是使用Animal、Dod和Cat,然后你可以说Animal=newdog或Animal=newcat,然后你可以调用它的虚拟函数,并自动调用适当的函数。这不是您的情况,因为您正在将函数DoSomething与new…重叠。您可以分配一个更通用的Foo和一个不太通用的Boo类型。这通常是在利用多态性时完成的。经典的例子是使用Animal、Dod和Cat,然后你可以说Animal=newdog或Animal=newcat,然后你可以调用它的虚拟函数,并自动调用适当的函数。这不是你的情况,因为你把函数与新的函数重叠了…如果你认为它只想实现由FoO所定义的功能,它可能会更有意义。Bar可以自由添加与任何Bar相关的更多功能
现在,调用代码只关心FO定义的抽象,因此,尽管事实上您正在创建BAR,但是您只得到FoO定义的契约,而不是BAR.ISFALID函数。这可能更有意义。Bar可以自由添加与任何Bar相关的更多功能
现在调用代码只关心Foo定义的抽象,因此,尽管您正在创建Bar,但您只得到Foo定义的契约,因此不是Bar。我刚刚定义的是有效的功能。我知道代码的用途,但我不明白的是,在创建子类的实例时,如何使用超类作为引用。如果超类方法是虚拟的,真的有什么好处吗?如果超类方法是虚拟的,会有什么不同吗?大多数其他答案都会深入讨论使用基类和/或接口inst的好处
具体类的ead—归根结底,您希望依赖于抽象而不是具体的东西,以便以后更改实际实现—这是多态性的基础,并使IoC/Dependency注入等功能更加强大我知道代码的目的,但我不明白的是,在创建子类的实例时,如何使用超类作为引用。如果超类方法是虚拟的,那么它真的有什么好处吗?如果超类方法是虚拟的,那么会有什么不同吗?大多数其他答案都会深入讨论使用基类和/或接口而不是具体类的好处-归结起来,您希望依赖于抽象而不是具体的东西,以便以后可以更改实际的实现on-这是多态性的基础,使IoC/依赖性注入等功能更加强大。您寻求的答案位于BrokenGlass的答案和Justin的答案与多态性的混合中。不幸的是,这种语义没有简单的答案。您需要熟悉工厂模式、IoC或依赖注入。工厂模式可能是最简单的模式。没有经验,你需要一本书来分解复杂的细节。头先设计模式是一个很好的选择。你要寻找的答案是BrokenGlass的答案和Justin的答案混合在一起的多态性。不幸的是,这种语义没有简单的答案。您需要熟悉工厂模式、IoC或依赖注入。工厂模式可能是最简单的模式。没有经验,你需要一本书来分解复杂的细节。头先设计模式是一个很好的选择。