我发现可以创建子类的实例并将其分配给父类的变量。我无法绕过这种情况。
在我的代码中,虽然实例是Human
类。它在控制台中记录“我是动物”
我对此有一些疑问:
它甚至意味着什么?
可能的结果是什么?
为什么&什么时候会有人做这种事情?
家长班:
public class Species
{
public String Shout()
{
return "I am an animal";
}
}
儿童班:
public class Human : Species
{
public new String Shout()
{
return "I am a Human";
}
}
实例化:
class Program
{
static void Main(string[] args)
{
Species h = new Human();
Console.WriteLine(h.Shout());
}
}
答案 0 :(得分:7)
如果要有效地使用面向对象编程或OOP,多态性非常有用。
假设您拥有一个动物园。在这个动物园里面(显然)有一些动物。如果您希望将它们全部存储在一个数组或列表中,则必须使用base type,在本例中为Animal
。现在,从我们的基类型Animal
派生的类共享相同的属性,因此也使用相同的方法。
class Animal
{
public string Shout ()
{
return "I am an animal!";
}
}
现在让我们为狮子宣布一个班级。
class Lion : Animal
{
}
即使我们没有在Shout
类中编写Lion
方法,Lion
的实例也也会使用Shout
方法可供他们使用,因为他们从Animal
类派生。
但是如果我们希望Lion
类与Shout
有所不同呢?我们可以使用virtual
和override
关键字。这些可用于属性和方法。 virtual
表示可以覆盖 的方法或属性,而override
执行实际覆盖。两者都需要为这个工作设置正确的位置。
要覆盖我们的Shout
方法,我们必须先将其标记为virtual
。
public virtual string Shout () { ... }
现在,在我们的Lion
课程中,我们可以对Shout
方法执行覆盖。
public override string Shout ()
{
return "Rooooaaar, I am a lion!";
}
现在我们澄清了这一点,让我们来看看它的一些用法。
Lion lion1 = new Lion();
这通过调用类的构造函数来创建Lion
类的新实例。如果我们现在致电lion1.Shout()
,我们会将"Rooooaaar, I am a lion!"
作为返回值。
Animal animal1 = new Lion();
这也有效!由于我们的Lion
类派生自基类型Animal
,因此该对象可以存储在类型Animal
的对象中。但不要被愚弄!如果我们现在致电animal1.Shout()
,我们仍然会返回"Rooooaaar, I am a lion!"
。
Animal animal2 = new Animal();
这只是基类的一个实例,这意味着方法animal2.Shout()
将返回"I am an animal!"
。
现在我们说我们还有更多动物,Cat
,Dog
和Lion
。不使用多态,我们无法将它们存储在单个数组中,因为它们没有任何共同之处!但是,如果它们来自Animal
类,我们可以这样做:
List<Animal> animals = new List<Animal>();
animals.Add(new Cat());
animals.Add(new Dog());
animals.Add(new Lion());
animals.Add(new Animal());
以上所有这些都可以完美地运作!
最后,如果您要从此Animal
列表中检索某个元素,并且想要在其上调用某些Dog
特定方法,则可以(如果它实际上是Dog
当然,使用animals[1] as Dog
将其转换为Dog
对象。但是,如果它不是Dog
对象,您只需从null
运算符返回as
。
答案 1 :(得分:2)
它甚至意味着什么?
Polymorphism - Poly 表示很多,变体表示表单
因此多态意味着有许多形式。在面向对象的编程范例中,多态性通常表示为一个接口,多个函数&#39;。 - Tutorials Point
可能的结果是什么?
从您的代码开始:
Species h = new Human();
Console.WriteLine(h.Shout()); //calling Shout method of Species
输出结果为:I am an animal
通过在类型中实例化Shout
,您在调用Species
(子级)的Human
(基本父级)的h
方法Species
。
为什么&amp;什么时候会有人做这种事情
同样在您的示例中,您可以在shout
Human
casting
方法
Console.WriteLine(((Human)h).Shout()); //calling Shout method of Human
输出结果为:I am an human
。
在此我将h
作为Human
投放((Human)h)
以提高可读性,您也可以执行h as Human
,然后调用Shout
Human
方法{1}}课程。
Console.WriteLine((h as Human).Shout()); //calling Shout method of Human
检查Fiddle
PS:您还应该注意@Willem所说的
你不应该使用新的。但要使Shout成为虚拟并在人类的呐喊中使用覆盖
基本上多态性是针对重载方法(检查覆盖和虚拟用法)进行的,但是具有不同的数据类型作为参数或不同的数据类型本身,在子类,父类或子和父之间
答案 2 :(得分:1)
不完全回答您的问题,但如果您希望代码显示“我是人”,请执行以下操作:
家长班:
public class Species
{
public virtual String Shout()
{
return "I am an animal";
}
}
儿童班:
public class Human : Species
{
public override String Shout()
{
return "I am a Human";
}
}
要完整回答您的问题,您应该查看有关多态性的教科书或文章。
答案 3 :(得分:0)
作为一个商业示例,您正在编写一个程序,您需要对某个对象执行特定操作。该对象之前可能已通过此程序,但需要采用不同的路径。您可以将其设置为使用多态并覆盖您需要更改的方法。例如:
对ImageProcess的基类进行成像,该基类具有ProcessPicture的覆盖。
ProcessPicture可能会在审核之前进行一些裁剪和清理,或者在另一个程序中从中提取数据。程序将其发回,但这次ProcessPicture需要添加水印。
通过这种方式,我们可以让一个程序根据图像的状态执行不同的任务。