【问题标题】:why to create type of parent class to store the object of child class?为什么要创建父类的类型来存储子类的对象?
【发布时间】:2018-10-01 06:55:01
【问题描述】:

我对 C# 中的多态性和继承有点困惑。 在学习多态性时,我发现了类似这样的东西 ParentClass P = new ChildClass();这有点令人困惑。为什么有人会创建父类的类型来存储子类的对象?但是它在 c# 中是有效的,我只想了解 3 件事: 1. 这样做的目的是什么? 2. 这样做有什么好处? 3. 什么时候应该创建这样的对象? 以下是我的参考代码:

using System;

class ParentClass
{
    public void Display()
    {
        Console.WriteLine("Display method in Parent class");
    }
}

class ChildClass : ParentClass
{
    public void Display()
    {
        Console.WriteLine("Display method in Child class");
    }
}

public class Program
{
    public static void Main()
    {
        ParentClass P = new ChildClass();
        P.Display();
    }
}

代码的输出是: Parent 类中的显示方法。

现在,如果有人必须调用父类中的方法,为什么不简单地创建 父类 P = 新父类(); 或者如果有人必须在 Child 类中调用方法,为什么不简单地创建 ChildClass C = new ChildClass();

翻了很多论坛,还是没有找到我想要的答案。如果有人可以用例子详细解释,那将是很大的帮助。谢谢。

【问题讨论】:

    标签: c# oop inheritance polymorphism


    【解决方案1】:

    多态性的整个想法是可以从派生类类型创建对象,但将它们视为基类类型。

    这样做的好处是,例如,假设您有一个获取十几个动物对象的方法。 当然,其中一些是狗,猫,鸟等

    为了处理这些对象而不必检查它们的类型,您可以将它们视为 Animal 基类,而不是它们创建的类型类。

    所以你可以在方法中得到一个动物列表,不用担心对象类型。

    虽然它们都是针对不同的对象类型创建的,但它们都派生自 Animal 类,因此它们共享一些方法和属性。

    【讨论】:

    • 嘿,谢谢 Ron F 的回答,我有点明白了,但如果能像你所说的那样用例子详细解释一下,十几个动物对象对我会有很大的帮助
    【解决方案2】:

    我可以举一个简单的例子,让我在你的位置上睁开眼睛。 假设我们要计算一些 2D 形状的面积:

    class Program
    {
        static void Main(string[] args)
        {
            List<Shape> shapes = new List<Shape>()
            {
                new Rectangle(5, 5),
                new Circle(2)
            };
    
            foreach (Shape shape in shapes) //even though we just have a "Shape" here the respective methods of "Rectangle" and "Circle" are executed
            {
                Console.WriteLine(shape.CalculateArea());
            }
    
            Console.ReadKey(true);
        }
    }
    
    public abstract class Shape
    {
        public abstract double CalculateArea();
    }
    
    public class Rectangle : Shape
    {
        private double a;
        private double b;
    
        public Rectangle(double a, double b)
        {
            this.a = a;
            this.b = b;
        }
    
        public override double CalculateArea()
        {
            return a * b;
        }
    }
    
    public class Circle : Shape
    {
        private double r;
    
        public Circle(double r)
        {
            this.r = r;
        }
    
        public override double CalculateArea()
        {
            return 2 * Math.PI * r;
        }
    }
    

    如您所见,我们有一个 Shape 的父类,并从中派生出 RectangleCircle。因为我们用public abstract double ClaculateArea() 告诉C#,所有子类都必须实现这样的功能。对于我们创建的每个子类,这种计算很可能会有所不同。这样做的好处是我们可以将来自Shape 的各种不同形状保存在一个列表中。但是如果我们在这些此时子类类型未知的项目中调用CalculateArea(),则会执行相应的计算函数。

    请注意,这只是此类构造如何有用的一个示例,但在我看来,这是最明显且易于理解的示例。

    【讨论】:

      【解决方案3】:

      通过允许我们将子类向上转换为更派生的类或基类,我们可以创建基类的集合,其中可以包含更多派生的元素。下面看一下使用CatDog 类的实际情况,这两个类都继承自Animal 基类:

      Cat c = new Cat();
      Dog d = new Dog();
      
      List<Animal> myPets = new List<Animal>();
      myPets.Add(c);
      myPets.Add(d); //no casting needed
      

      所以说Animal 基础有一个保存年龄的属性:

      public int Age { get; set; }
      

      因为我们已经隐含地表示 my Cat c 和 Dog d 是 Animal 类型,所以我们可以在不进行任何转换的情况下调用此类型,这很有用。

      Foreach(Animal a in myPets)
         Console.WriteLine(a.Age);
      

      这对于我们在 Asp.Net 中具有 asp:Panel 或在包含子项(可能是 labeltextbox 等的集合)的 winform 中具有 Panel 的控件集合很有用包含每个项目的List,我们可以将它们向上转换到它们都共享的基础,即Control 类,允许我们将子项目或节点的集合作为Controls 的集合保存,并且当我们想做一些操作,我们可以将其向下转换为更派生的类型(使用as/is

      这在委托中也很有用,当创建一个委托时,我们可以分配一个比它返回的更派生的类型,从而可以为多种不同的类型重用。这对于泛型类型的集合也是如此。您应该在链接上阅读更多内容,因为它有很好的示例。

      这是协变和逆变

      在 C# 中,协变和逆变支持数组类型、委托类型和泛型类型参数的隐式引用转换。协变保持赋值兼容性,而逆变反转它。

      Further reading

      【讨论】:

        【解决方案4】:

        1.目的,a)你必须先调用子类构造函数,然后再调用父类成员,

        2.优点,a)用于调用子类构造函数。

        3.When To Use, a)当需要先访问子类构造函数,再访问父类成员时。

        代码

        class ParentClass
        {
            public void Display()
            {
                Console.WriteLine("Display method in Parent class");//second get executed
            }
        }
        
        class ChildClass : ParentClass
        {
            public ChildClass(string x)//first get executed
            {
                Console.WriteLine(x);
            }
            public void Display1()
            {
                Console.WriteLine("Display method in Child class");
            }
        }
        
        public class Program
        {
            public static void Main()
            {
                ParentClass P = new ChildClass("First get Executed");
                P.Display();
                Console.ReadKey();
            }
        }
        

        【讨论】:

          【解决方案5】:

          有一些限制。通过 Parent 调用 DerivedClasses/Child Class 可能不是正确的方法。无论是缺点还是限制,我都会自行解释

          最终在一个项目中创建父类和派生类 和另一个具有 ParentClass 类型属性的类

          并使所有父子类都为内部类

          using System;
          
          
          namespace Logic
          {
              public class IndraDhanush
              {
                  public Vehicle[] VehiclesLocal { get; set; }
          
                  public IndraDhanush(Vehicle[] vehicles)
                  {
                      this.VehiclesLocal = vehicles;
                  }
              }
              internal class Vehicle
              {
              }
              internal class FourWheeler : Vehicle
              {
              }
              internal class Car : FourWheeler
              {
              }
              internal class PetrolCar : Car
              {
              }
              internal class ElectricCar : Car
              {
              }
          }
          

          现在在另一个项目中引用这个类库 现在制作一个将父类存储为类成员的类的对象

              static void Main(string[] args)
              {
                  IndraDhanush indraDhanush = new IndraDhanush(new Vehicle[] { new Vehicle(), new FourWheeler(), new Car(), new ElectricCar() });
              }
          

          好吧,我们可以尝试避免这种情况 > 我们可以尝试将 Vehicle Class 设为 Public,但仍然无法访问 Child 类。

          也可以添加图像格式的代码。 Image for Both Projects

          【讨论】:

            猜你喜欢
            • 2013-06-17
            • 1970-01-01
            • 2015-11-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-10
            • 2013-12-06
            • 1970-01-01
            相关资源
            最近更新 更多