在我的例子中,继承发生了什么?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();

  1. 当我声明Animal并将其设置为Dog引用时,实际发生了什么?这有什么专门的术语吗?
  2. 当我调用a.Hungry()时,输出是"狗说话"。如果输出是"Dog Speak",为什么我不能调用a.Fetch() ?用什么术语来描述这里发生的事情?

任何帮助和进一步阅读的特定主题将不胜感激。

在我的例子中,继承发生了什么?c#中合适的术语是什么?

  1. 这是一个"向上转换"。在c#中有一个从任何类型到它的任何基本类型的隐式转换,所以你不需要做任何事情来对待Dog,就好像它是Animal一样。(感谢Matt Burland提醒我这是一个合适的术语。)
  2. 因为变量的类型是Animal,因此你只能访问编译器知道Animal可以访问的成员,即SpeakHungry。它不知道AnimalDog,所以它不能调用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,但由于aDog而不是基本的Animal,因此它将调用Dog.Speak方法(正如Servy在其他地方指出的那样,这是真正的多态性-调用特定方法时实际执行的代码将根据对象的实际类型而有所不同)。

  1. aAnimal引用,它指向Dog对象。这是多态性(子类型多态性)的一种形式。

  2. 你不能调用a.Fetch,因为a有类型AnimalFetch方法没有在你的Animal类中定义。

  1. 您正在将Dog类型的对象存储在一个变量中,该变量将接受任何Animal。这被称为多态性(实际上不太见Servy的评论)
  2. 你只能通过先将对象强制转换为狗来调用fetch

一样:

Dog dog = (Dog)a;
dog.Fetch();

否则,据编译器所知,它可以是任何动物,并不是所有的动物都有Fetch方法。还要注意,如果它实际上不是Dog对象,则强制转换将抛出InvalidCastError

这个词是多态性

  1. 因为你的动物恰好被实例化为Dog,它将执行Dog的所有方法。AnimalDog都有一个Speak方法,DogAnimal继承了HungryDogspeak方法覆盖了Animal's,所以这就是执行的。

  2. 不能写a.Fetch的原因是编译器在设计时不知道。

例如

Animal a;
if(console.ReadLine() == "Dog")
{
    a = new Dog();
}
else
{
    a = new Animal();
}
a.Fetch();

此时当你调用a.Fetch时你不知道a是否是一只狗

  1. 当您声明Animal并将其设置为dog时,就完成了隐式强制转换
  2. 试试这段代码,看看使用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?