好的,所以我遇到了这个代码片段:
class1 a = new class1();
a.Test();
class1 b = new class2();
b.Test();
它与虚拟和覆盖有关,但我现在的问题是:为什么要输入
class1 b = new class2();
当你可以输入
class2 b = new class2();
因为两种解决方案具有相同的输出
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)。
可以说,B1
两者B2
都来自A
. 那么你可能直到运行时才知道你是否拥有 aB1
或B2
. 在这种情况下,您必须静态概括A
哪个可以同时容纳这两种子类型。如果正确使用继承,您就不会关心具体的运行时类型是什么。
例子:
A a = GetA();
A GetA() {
if (Random()) return new B1();
else return new B2();
}
因为它可以是B1
and B2
,所以您必须A
为变量类型 ( )使用公共基类。
在方法上使用“new”关键字而不是“override”的派生类的行为会有所不同,具体取决于它的转换方式。
例子:
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 使用“覆盖”关键字“覆盖”类 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"
因为类 2“隐藏”了该方法,所以当用作自己的类型时会输出“Class2.DoSomething”,但在用作其基本类型时会输出“Class1.DoSomething”。但是因为第 3 类“覆盖”了该方法,所以无论是用作自己的类型还是基类型,它都会输出“Class3.DoSomething”——因为它“覆盖”了基类型的功能。
(这样做的另一个影响是,如果Class2
或Class3
有一个额外的方法,比如说DoSomethingElse
,你将无法调用Class1 two = new Class2(); two.DoSomethingElse()
,因为Class1
没有那个方法。)
我不知道任何现实世界的用例,但它就在那里,这是我能想到的唯一方法 usingClass1 class2 = new Class2()
会提供任何实际用途。如果Class2
不“隐藏” 的任何成员Class1
,则没有真正的好处。
这是一个抽象和松耦合的问题。如果代码只依赖于'class1'的类型而不是'class2'的细节(这是class1的一个特定子类),那么代码更通用,您可以轻松切换到class1的不同子类型而无需更改其他代码。
一个例子:假设你有一个抽象List
类。它有两个子类,ArrayList
和LinkedList
。它们的工作方式或多或少相同(作为项目列表),但实现方式不同,从而赋予它们不同的性能特征。当您编写代码时,您不确定哪种实现最适合您的代码。因此,您希望以不依赖于任何特定子类的细节的方式编写代码。
如果您的代码只关心该类是 a List
,那么您只需要命名具体的子类一次:
List x = new LinkedList();
在其他任何地方,您都可以将其视为更一般的List
类。这确保了两件事:
ArrayList
insted of LinkedList
,您只需在一处更改代码。例如,List
将定义一些方法和属性,例如 sayCount
和Item
,然后将被所有子类支持。但是特定的子类也可能定义额外的方法,比如Resize
forArrayList
和IsCircular
for LinkedList
,这仅对特定的子类有意义。
通过将变量声明为更通用的类型,List
您可以确保您不会依赖某些特定于子类的方法或属性,因为编译器不会让您使用它们。
这称为多态性。简而言之,它允许您创建多个子类并将它们视为父类,这具有一些优点,例如防止代码重复。
我将添加另一个答案来解决为什么有人在他的头脑中会完全像那样键入它的问题。
唯一可能表现不同的情况是如果class2
两者class1
都有同名的方法,但不使用虚拟继承。这可以通过new
关键字来完成(或者根本没有关键字,它会编译但会触发当之无愧的警告)。
这是一种糟糕的风格,几乎从来没有用过。这可能不是他的本意。
以这种方式编写它以记录仅使用成员的事实可能仍然有意义class1
。他可能会说它确实是class2
在运行时的事实并没有发挥作用。这很可能是因为虚拟继承。
所以这可能纯粹是为了记录意图。
我可以解释Java中的情况,同样适用于C#
从下面的代码中,我创建了一个引用 World 类的 Object (obj)。
由于 World 扩展了 India 和 Belgium 类,我们可以使用相同的 Object (obj) 来访问这两个类的方法,这种表示法是为了提高代码的效率。遵循相同的符号也不是强制性的。
希望我已经回答了您的问题,如果有任何疑问,请告诉我:)
类世界{
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");
}
} 公共课地理 {
public static void main(String[] args){
World obj; // Declaring an Object referencing World Super Class
obj = new India(); // Allocating M/m to India class (All V & M Ind & World Class)
obj.printName();
// Allocating Same Object M/m to Belgium class (All V & M BGM & World Class)
obj = new Belgium();
obj.printName();
}
}
您可以在“工厂”模式中使用这个实例化示例。这是我能想到的第一个用法。