为什么我会将class2的引用放入class1的对象中?

时间:2013-09-08 16:11:35

标签: c# class

好的,所以我遇到了这段代码:

class1 a = new class1();
a.Test();

class1 b = new class2();
b.Test();

它与虚拟和覆盖有关,但我现在的问题是: 为什么要输入

class1 b = new class2();

当你可以输入

class2 b = new class2();

因为两个解决方案都具有相同的输出

8 个答案:

答案 0 :(得分:2)

class1显然是class2的超类。这样你就可以得到一个class1对象列表,它们都包含class1或class2对象。您可以简单地将a和b添加到该列表中。

class Class1 {
   public virtual void test(){
       //do something
   {
}

class Class2 : Class1 {
   public override void test(){
      // do something else
   }
}

IList<Class1> list = new List<Class1>();
Class1 a = new Class1();
Class1 b = new Class2();
list.add(a);
list.add(b);

然后,尝试从该列表中获取项目,您只需执行以下操作:

list[0].test(); //calls test of Class1
list[1].test(); //calls test of Class2

这个概念叫做多态(poly = many,morph = shape)。

答案 1 :(得分:1)

让我们说,B1B2 两者都来自A。然后,您可能直到运行时才知道您是B1还是B2。在这种情况下,您必须静态推广到A,它可以容纳两种子类型。如果正确使用了继承,则不关心具体的运行时类型是什么。

示例:

A a = GetA();

A GetA() {
 if (Random()) return new B1();
 else return new B2();
}

因为它可以是B1B2,所以必须为变量类型(A)使用公共基类。

答案 2 :(得分:1)

在方法上使用“new”关键字而不是“覆盖”的派生类将根据其投射方式而有所不同。

示例:

class Class1
{
    public virtual void DoSomething
    {
        Console.WriteLine("Class1.DoSomething");
    }
}

class Class2 : Class1
{
    public new void DoSomething
    {
        Console.WriteLine("Class2.DoSomething");
    }
}

class Class3 : Class1
{
    public override void DoSomething
    {
        Console.WriteLine("Class3.DoSomething");
    }
}

类2和3派生自类1,但类2使用'new'关键字来“隐藏”类1的虚拟成员,而类3使用'override'关键字来“覆盖”类的虚拟成员1.当你在他们自己的类型的幌子下使用这些类时会发生什么:

Class1 one = new Class1();
one.DoSomething(); // outputs "Class1.DoSomething"
Class2 two = new Class2();
two.DoSomething(); // outputs "Class2.DoSomething"
Class3 three = new Class3();
three.DoSomething(); // outputs "Class3.DoSomething"

他们都按预期输出正确的类名。但是当你在第1类的幌子下使用这些类时会发生这种情况:

Class1 one = new Class1();
one.DoSomething(); // outputs "Class1.DoSomething"
Class1 two = new Class2();
two.DoSomething(); // outputs "Class1.DoSomething"
Class1 three = new Class3();
three.DoSomething(); // outputs "Class3.DoSomething"

因为class 2'隐藏'了这个方法,所以当它用作自己的类型时会输出'Class2.DoSomething',但是当它用作它的基类型时它会输出'Class1.DoSomething'。但是因为类3'覆盖'了该方法,所以它将输出'Class3.DoSomething',无论它是用作自己的类型还是基类型 - 因为它'覆盖'基类型的功能。

(这样做的另一个影响是,如果Class2Class3有其他方法,比如DoSomethingElse,您将无法拨打Class1 two = new Class2(); two.DoSomethingElse(),因为{ {1}}没有那种方法。)

我不知道任何现实世界的用例,但它就在那里,而且我认为使用Class1提供任何实际用途的唯一方法。如果Class1 class2 = new Class2()没有“隐藏”Class2的任何成员,那么就没有真正的好处。

请参阅:http://msdn.microsoft.com/en-us/library/ms173153.aspx

答案 3 :(得分:1)

这是一个抽象和松散耦合的问题。如果代码只依赖于'class1'的类型而不是'class2'(class1的特定子类)的细节,那么代码更通用,你可以轻松切换到class1的不同子类型而不改变其他代码。

一个例子:假设您有一个抽象的List类。它有两个子类ArrayListLinkedList。它们或多或少地相同(作为项目列表),但是以不同的方式实现,从而赋予它们不同的性能特征。编写代码时,您不确定哪种实现最适合您的代码。因此,您希望编写代码的方式使您不依赖于任何特定子类的详细信息。

如果您的代码只关心该类是List,那么您只需要命名具体的子类一次:

List x = new LinkedList();

在其他任何地方,您都可以将其视为更一般的List类。这确保了两件事:

  • 如果您决定使用ArrayList LinkedList,则只需在一个地方更改代码。
  • 您不会意外地依赖于其中一个具体子类的实现特定细节,例如:通过调用仅存在于其中一个上的方法。通过强制转换为基类,类型检查器可确保您只能调用所有子类共享的方法。这也意味着您可以更轻松地交换实施。

例如,List将定义一些方法和属性,例如说CountItem,然后所有子类都支持这些方法和属性。但是特定的子类可能还定义了其他方法,例如Resize的{​​{1}}和ArrayList的{​​{1}},只对特定的子类有意义。

通过将变量声明为更通用的类型IsCircular,您可以确保不依赖于某些特定于子类的方法或属性,因为编译器很简单,不允许您使用它们

答案 4 :(得分:0)

这称为Polymorphism。简而言之,它允许您创建多个子类并将它们视为父类,这具有一些优点,例如防止代码重复。

答案 5 :(得分:0)

我会添加另一个答案,以解决为什么某个人,在他的正确思想中,会像那样输入它。

唯一可能表现不同的情况是,class2class1都有一个具有相同名称的方法,但不使用虚拟继承。这可以使用new关键字完成(或者根本没有关键字可以编译,但会触发当之无愧的警告)。

这是糟糕的风格,几乎从未有用。这可能不是他想要的。

以这种方式编写它可能仍然有意义,以记录仅使用class1成员的事实。他可能会说,它在运行时确实是class2这一事实并不起作用。这很可能是因为虚拟继承。

所以这可能仅仅是为了记录意图。

答案 6 :(得分:0)

我可以解释Java的情况,同样适用于C#

从下面的代码中,我创建了一个引用World类的Object(obj)。

由于World扩展了印度和比利时的类,因此我们可以在访问这两个类的方法时使用相同的对象(obj),这种表示法是为了提高代码的效率。 遵循相同的符号也不是强制性的。

希望我已经回答了您的问题,如有任何疑问,请告诉我:)

世界级{

name1

}

印度阶级扩展了世界{

public void printName() {

    System.out.println("Name is: World");
}

} 比利时类别扩展了世界{

public void printName() {

    System.out.println("Name is: India");
}

} 公共课地理{

public void printName() {

    System.out.println("Name is: Belgium");
}

}

答案 7 :(得分:-1)

您可以在“工厂”模式中使用此实例进行实例化。这是我能想到的第一个用法。