【问题标题】:c# Instantiate object from subclassc# 从子类实例化对象
【发布时间】:2019-06-03 17:11:25
【问题描述】:

下面我有一些简单的代码,其中包含一个父类和一个从它扩展的子类。

使用系统;

//Base Class
public class Parent {
    public void foo() {
        Console.WriteLine("Parent");
    }
}

//Child Class
public class Child : Parent
{
    new public void foo() {
        Console.WriteLine("child");
    }
}

Parent parent = new Child();
parent.foo();

我对上面两行的工作方式感到困惑。我本来希望编译器在尝试将 Parent 实例化为其自己的子类时会吠叫。另外,为什么'parent.foo()'仍然会调用它的父版本。

【问题讨论】:

  • 为什么您认为您无法实例化Parent 对象?毕竟,Parent 类只是一个沼泽标准、普通、普通、普通的类。从Parent 继承的另一个类不会使Parent 不可实例化(此外,编译器通常不会崩溃。如果编译器对您的源代码有问题,编译器会发出错误消息,但不会崩溃...)
  • 您将方法覆盖与阴影混合在一起。而且,您还应该阅读有关 OOP 的基本教程。我建议您阅读 Microsoft Docs 上的官方文档。喜欢这个:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
  • 嗯,Child 实例本质上也是Parent 实例(因为Child 类继承自Parent),因此为什么Child 实例可以被视为它是一个Parent 实例(包括将Child 实例分配给Parent 类型的变量/具有Parent 类型的引用/变量引用Child 实例)。关于方法调用:您没有覆盖子方法,而是在做所谓的“成员/方法隐藏”(也称为“成员隐藏”,请参阅我之前的 Camilo 评论)
  • 由于Child 扩展了Parent,您可以说ChildParent。当一个类继承/扩展另一个类时,可以将其声明为它继承/扩展的类。因为它被声明为Parent,所以您将只能使用Parent 上的方法,即使运行时将该类实例化为Child 类。
  • 关于成员隐藏/隐藏,您可能想在这里阅读:stackoverflow.com/questions/3838553/overriding-vs-method-hiding(另外,一般不要使用成员隐藏。在没有真正了解它的作用的情况下随意使用成员隐藏会导致程序中的错误和意外行为)

标签: c# inheritance polymorphism


【解决方案1】:

首先你不应该使用new关键字隐藏基类方法,你应该使用virtualoverride关键字通过派生类方法覆盖它。它还将解决从基类而不是派生类调用方法的问题。

有关其工作原理的详细信息,您应该阅读inheritance in C#

当您使用new 关键字隐藏方法时,它始终使用您声明的类型中的方法实现,在您的情况下为Parent。但是,如果您使用 virtualoverride 它使用初始化类型的方法的实现,在您的情况下它是 Child

using System;

public class Parent 
{
    public virtual void foo() 
    {
        Console.WriteLine("Parent");
    }
}

public class Child : Parent
{
    public override void foo() 
    {
        Console.WriteLine("Child");
    }
}

【讨论】:

    【解决方案2】:

    为什么'parent.foo()' 仍然调用它的父版本?

    因为您正在使用 new 跟踪 foo

    子类可以覆盖虚拟或抽象方法:

    //Base Class
    public class Parent
    {
        public virtual void foo()
        {
            Console.WriteLine("Parent");
        }
    }
    
    //Child Class
    public class Child : Parent
    {
        public override void foo()
        {
            Console.WriteLine("child");
        }
    }
    

    我会阅读 cmets 中链接的所有文档,以确定哪种方法最适合您的用例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多