在我的例子中,继承发生了什么?c#中合适的术语是什么?
本文关键字:是什么 术语 发生了 我的 继承 什么 | 更新日期: 2023-09-27 17:54:12
我正在学习OOP,有一个问题,下面的代码到底发生了什么。
我有一个经典的Dog
Animal
的例子。Dog
继承Animal
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";
}
}
这两个问题都是基于这个作业:Animal a = new Dog();
- 当我声明
Animal
并将其设置为Dog
引用时,实际发生了什么?这有什么专门的术语吗? - 当我调用
a.Hungry()
时,输出是"狗说话"。如果输出是"Dog Speak",为什么我不能调用a.Fetch()
?用什么术语来描述这里发生的事情?
任何帮助和进一步阅读的特定主题将不胜感激。
- 这是一个"向上转换"。在c#中有一个从任何类型到它的任何基本类型的隐式转换,所以你不需要做任何事情来对待
Dog
,就好像它是Animal
一样。(感谢Matt Burland提醒我这是一个合适的术语。) - 因为变量的类型是
Animal
,因此你只能访问编译器知道和Animal
可以访问的成员,即Speak
和Hungry
。它不知道Animal
是Dog
,所以它不能调用Fetch
。变量需要为Dog
类型,以便您能够在其上调用Fetch
。
Animal a = new Dog();
向上转型。您正在创建一个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();
这是允许的,因为Animal
有一个Hungry
方法。Hungry
方法称为Speak
,但由于a
是Dog
而不是基本的Animal
,因此它将调用Dog.Speak
方法(正如Servy在其他地方指出的那样,这是真正的多态性-调用特定方法时实际执行的代码将根据对象的实际类型而有所不同)。
-
a
是Animal
引用,它指向Dog
对象。这是多态性(子类型多态性)的一种形式。 -
你不能调用
a.Fetch
,因为a
有类型Animal
和Fetch
方法没有在你的Animal
类中定义。
- 您正在将
Dog
类型的对象存储在一个变量中,该变量将接受任何Animal
。这被称为多态性(实际上不太见Servy的评论) - 你只能通过先将对象强制转换为狗来调用fetch
一样:
Dog dog = (Dog)a;
dog.Fetch();
否则,据编译器所知,它可以是任何动物,并不是所有的动物都有Fetch
方法。还要注意,如果它实际上不是Dog
对象,则强制转换将抛出InvalidCastError
。
这个词是多态性
-
因为你的动物恰好被实例化为
Dog
,它将执行Dog
的所有方法。Animal
和Dog
都有一个Speak
方法,Dog
从Animal
继承了Hungry
。Dog
的speak
方法覆盖了Animal's
,所以这就是执行的。 -
不能写
a.Fetch
的原因是编译器在设计时不知道。
Animal a;
if(console.ReadLine() == "Dog")
{
a = new Dog();
}
else
{
a = new Animal();
}
a.Fetch();
此时当你调用a.Fetch
时你不知道a是否是一只狗
- 当您声明
Animal
并将其设置为dog
时,就完成了隐式强制转换 - 试试这段代码,看看使用
virtual
和不使用它的效果。
:
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();
}
如果你用一只狗创建一个动物,你只创建了一个动物,并且只有动物的属性。这有一个简单的理由。只是一个例子:
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"
,但如果你现在改变一个像这样:a = new Cat()
,你可以调用a.Speak()
,但它返回别的东西…同样的召唤,不同的回报。当然,如果你确定动物确实是一只狗,你可以将它强制转换回显式实现。
var d= new Dog();
if(a is Dog)
d = a as Dog;
d现在是一只真正的狗,能做只有狗能做的一切,但你不能再把d指定为猫了。因为它是狗而不是动物
为什么是as而不是Cast?