在我的示例中,继承发生了什么?那么,c#的正确术语是什么?
我正在学习OOP,对下面的代码到底发生了什么有疑问 我有经典的在我的示例中,继承发生了什么?那么,c#的正确术语是什么?,c#,oop,C#,Oop,我正在学习OOP,对下面的代码到底发生了什么有疑问 我有经典的狗动物例子狗继承动物 public class Animal { public string Name { get; set; } public virtual string Speak() { return "Animal Speak"; } public string Hungry() { return this.Speak(); } }
狗
动物
例子<代码>狗继承动物
public class Animal
{
public string Name { get; set; }
public virtual string Speak()
{
return "Animal Speak";
}
public string Hungry()
{
return this.Speak();
}
}
public class Dog : Animal
{
public override string Speak()
{
return "Dog Speak";
}
public string Fetch()
{
return "Fetch";
}
}
这两个问题都是基于这个作业:animala=新狗()代码>
当我声明一个动物
并将其设置为狗
引用时,实际发生了什么。有专门的术语吗李>
当我调用a.Hungry()
时,输出是“Dog Speak”。如果输出是“Dog Speak”,为什么我不能调用a.Fetch()
?这里发生的事情的术语是什么
如果您能提供帮助并进一步阅读,我们将不胜感激
您正在将类型为Dog
的对象存储在一个变量中,该变量将接受任何动物
。这被称为(实际上并没有看到Servy的评论)
您只能通过首先将对象投射给狗来调用fetch
像这样:
Dog dog = (Dog)a;
dog.Fetch();
否则,就编译器所知,它可能是任何动物,并且并非所有动物都有方法Fetch
。还要注意的是,如果不是一个狗
对象,施法者会抛出一个InvalidCastError
a
是一个动物
参考,它指向一个狗
对象。这是多态性的一种形式(子类型多态性)
您不能调用a.Fetch
,因为a
具有类型Animal
,并且Fetch
方法未在Animal
类中定义
这是一个“向上投射”。在C#中,存在从任何类型到其任何基本类型的隐式转换,因此您不需要做任何事情来将狗
视为动物
。(感谢Matt Burland提醒我这是一个合适的术语。)
因为变量的类型是Animal
,因此您只能访问编译器知道Animal
可以访问的成员,即Speak
和hunger
。它不知道动物
是狗
,因此无法调用获取
。变量的类型必须是Dog
,才能调用Fetch
这个词就是多态性
因为您的动物恰好被实例化为狗
,它将执行狗
的所有方法。Animal
和Dog
都有一个Speak
方法,而Dog
从Animal
继承饥饿的Dog
方法重写动物的,所以执行的就是这个
无法编写a.Fetch
的原因是编译器在设计时不知道这一点
比如说
Animal a;
if(console.ReadLine() == "Dog")
{
a = new Dog();
}
else
{
a = new Animal();
}
a.Fetch();
此时,当您调用a.Fetch
时,您不知道a是否是狗如果您使用狗创建动物,您只创建了一个动物,并且只有动物的属性。原因很简单。举个例子:
public class Animal
{
public string Name { get; set; }
public virtual string Speak()
{
return "Animal Speak";
}
public string Hungry()
{
return this.Speak();
}
}
public class Dog : Animal
{
public override string Speak()
{
return "Dog Speak";
}
public string Fetch()
{
return "Fetch";
}
}
public class Cat: Animal
{
public override string Speak()
{
return "Cat Speak";
}
public string Fetch()
{
return "Fetch";
}
}
所以如果你现在像这样把一个疯子关起来:
Animal a = new Dog();
你知道你的动物会说话,他饿了,你只需要知道,你可以调用a.Speak()
,你的动物会返回“Dog Speak”
buf,如果你现在这样更改a:a=new Cat()
你也可以调用a.Speak()
,但它会返回其他东西。。。相同的呼叫但不同的返回。当然,如果您确定动物真的是一只狗,那么您可以将其返回到显式实现
var d= new Dog();
if(a is Dog)
d = a as Dog;
d现在是一只真正的狗,可以做任何只有狗才能做的事情,但你不能再把d指定为猫了。因为它是狗而不是动物
他在向上投射。您正在创建一个Dog
对象,并将其分配给父类的变量。这是允许的,但是
a.Fetch();
不行。为什么,因为Animal
没有名为Fetch
的方法,而且据编译器所知,a
可以是任何Animal
。如果您想调用Fetch
,您需要将a
转换回Dog
Dog d = (Dog)a;
d.Fetch();
但是请注意,如果a
不是Dog
,这将导致错误,因此通常先检查:
if (a is Dog)
{
Dog d = (Dog)a;
d.Fetch();
}
当你打电话的时候
a.Hungry();
这是允许的,因为动物
有一个饥饿
方法。饥饿的方法称为Speak
,但由于a
是一只Dog
,而不是基本的Animal
,它将称为Dog.Speak
方法(正如Servy在其他地方指出的那样,这是真正的多态性——调用特定方法时执行的实际代码会根据对象的实际类型而有所不同)
当您声明一个动物
并将其设置为狗
时,隐式强制转换完成
请尝试此代码以查看使用virtual
和不使用它的效果
:
对#1而言,这并不完全是多态性。多态性是指在类型动物的定义中调用a
的方法可能无法实现,它可以(在本例中,是)执行派生类型中定义的方法。因此,在<代码>动物<代码>中对<代码>狗<代码>进行攻击的能力不是多态性,事实上<代码>说话<代码>的结果是<代码>“狗说话”
,这是多态性。如果该方法不是虚拟的,它就不会是多态性的,因此会说<代码>“动物说话”
,但你仍然可以将狗
放入动物
变量中,而不使用多态性。有趣的是,我实际上认为这是多态性一词的正确用法,谢谢你提供的信息。每天学习新的东西!这实际上是
a.Hungry();
public class Animal
{
public string Name { get; set; }
public string Speak()
{
return "Animal Speak";
}
public string Hungry()
{
return this.Speak();
}
}
public class Dog : Animal
{
public new string Speak()
{
return "Dog Speak";
}
public string Fetch()
{
return "Fetch";
}
}
static void Main(string[] args)
{
Animal a = new Dog();
Console.WriteLine(a.Hungry()); //Animal Speak
Console.ReadLine();
}