好的,所以我遇到了这段代码:
class1 a = new class1();
a.Test();
class1 b = new class2();
b.Test();
它与虚拟和覆盖有关,但我现在的问题是: 为什么要输入
class1 b = new class2();
当你可以输入
时class2 b = new class2();
因为两个解决方案都具有相同的输出
答案 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)
让我们说,B1
和B2
两者都来自A
。然后,您可能直到运行时才知道您是B1
还是B2
。在这种情况下,您必须静态推广到A
,它可以容纳两种子类型。如果正确使用了继承,则不关心具体的运行时类型是什么。
示例:
A a = GetA();
A GetA() {
if (Random()) return new B1();
else return new B2();
}
因为它可以是B1
和B2
,所以必须为变量类型(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',无论它是用作自己的类型还是基类型 - 因为它'覆盖'基类型的功能。
(这样做的另一个影响是,如果Class2
或Class3
有其他方法,比如DoSomethingElse
,您将无法拨打Class1 two = new Class2(); two.DoSomethingElse()
,因为{ {1}}没有那种方法。)
我不知道任何现实世界的用例,但它就在那里,而且我认为使用Class1
提供任何实际用途的唯一方法。如果Class1 class2 = new Class2()
没有“隐藏”Class2
的任何成员,那么就没有真正的好处。
答案 3 :(得分:1)
这是一个抽象和松散耦合的问题。如果代码只依赖于'class1'的类型而不是'class2'(class1的特定子类)的细节,那么代码更通用,你可以轻松切换到class1的不同子类型而不改变其他代码。
一个例子:假设您有一个抽象的List
类。它有两个子类ArrayList
和LinkedList
。它们或多或少地相同(作为项目列表),但是以不同的方式实现,从而赋予它们不同的性能特征。编写代码时,您不确定哪种实现最适合您的代码。因此,您希望编写代码的方式使您不依赖于任何特定子类的详细信息。
如果您的代码只关心该类是List
,那么您只需要命名具体的子类一次:
List x = new LinkedList();
在其他任何地方,您都可以将其视为更一般的List
类。这确保了两件事:
ArrayList
LinkedList
,则只需在一个地方更改代码。例如,List
将定义一些方法和属性,例如说Count
和Item
,然后所有子类都支持这些方法和属性。但是特定的子类可能还定义了其他方法,例如Resize
的{{1}}和ArrayList
的{{1}},只对特定的子类有意义。
通过将变量声明为更通用的类型IsCircular
,您可以确保不依赖于某些特定于子类的方法或属性,因为编译器很简单,不允许您使用它们
答案 4 :(得分:0)
这称为Polymorphism。简而言之,它允许您创建多个子类并将它们视为父类,这具有一些优点,例如防止代码重复。
答案 5 :(得分:0)
我会添加另一个答案,以解决为什么某个人,在他的正确思想中,会像那样输入它。
唯一可能表现不同的情况是,class2
和class1
都有一个具有相同名称的方法,但不使用虚拟继承。这可以使用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)
您可以在“工厂”模式中使用此实例进行实例化。这是我能想到的第一个用法。