5

我正在学习 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()?这里发生的事情的术语是什么?

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

4

7 回答 7

5
  1. 这是一个“上流”。在 C# 中,存在从任何类型到其任何基本类型的隐式转换,因此您无需执行任何操作即可将 aDog视为Animal. (感谢 Matt Burland 提醒我这是合适的术语。)
  2. 因为变量的类型是Animal,因此您只能访问编译器知道可以访问的成员Animal,即Speakand Hungry。它不知道Animal是 a Dog,所以它不能调用Fetch。该变量需要是类型Dog才能调用Fetch它。
于 2013-01-18T19:40:58.383 回答
4
Animal a = new Dog();

正在上扬。您正在创建一个Dog对象并将其分配给父类的变量。这是允许的,但是...

a.Fetch();

不会工作。为什么,因为Animal没有一个名为 的方法Fetch,而且据编译器所知,a可以是 any Animal。如果你想打电话Fetch,你需要a转回一个Dog

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

a但是请注意,如果不是 a ,这将导致错误Dog,因此通常您首先检查:

if (a is Dog) 
{
    Dog d = (Dog)a;
    d.Fetch();
}

你打电话时

a.Hungry();

这是允许的,因为Animal有一个Hungry方法。Hungry调用的方法Speak,但由于a是 aDog而不是 base Animal,它将调用该Dog.Speak方法(正如 Servy 在其他地方指出的那样,这是真正的多态性 - 调用特定方法时执行的实际代码的想法将根据实际情况而有所不同对象的类型)。

于 2013-01-18T19:45:35.360 回答
2
  1. 您正在将一个类型的对象存储Dog在一个变量中,该变量将接受任何Animal. 这被称为多态 (实际上不太看Servy的评论)
  2. 您只能通过首先将对象投射到狗来调用 fetch

像这样:

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

否则,据编译器所知,它可能是任何动物,并且并非所有动物都有方法FetchInvalidCastError另请注意,如果它实际上不是一个Dog对象,则演员会抛出一个。

于 2013-01-18T19:40:00.243 回答
2
  1. a是一个Animal引用,它指向一个Dog对象。这是多态性的一种形式(亚型多态性)。

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

于 2013-01-18T19:40:27.057 回答
1

这个词是多态性

  1. 因为您的动物恰好被实例化为 a Dog,它将执行所有Dog的方法。两者都有一个方法,Animal并且继承自. 的方法覆盖,所以这就是被执行的。DogSpeakDogHungryAnimalDogspeakAnimal's

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

例如

Animal a;

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

a.Fetch();

在这一点上,当您打电话时,a.Fetch您不知道 a 是否是狗

于 2013-01-18T19:42:09.557 回答
0

如果你用狗创建动物,你只创建了一个动物,并且只有动物的属性。这有一个简单的原因。只是一个例子:

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";
    }
}

所以如果你现在像这样创建一个 Insance:

Animal a = new Dog();

你知道你的动物会说话而且他饿了,这就是你需要知道的一切,你可以打电话,如果你现在改变这样a.Speak(),你的动物会返回buf:你也可以打电话,但它会返回别的东西.. . 相同的调用但不同的返回。当然,如果您确定 Animal 确实是 Dog,您可以将其强制转换回 Explicit 实现。"Dog Speak"a = new Cat()a.Speak()

var d= new Dog();
if(a is Dog)
d = a as Dog;

d 现在是一只真正的 Dog,它可以做只有 Dog 才能做的所有事情,但你不能再将 d 指定为 Cat。因为它是狗而不是动物

为什么 as 而不是 Cast?

于 2013-01-18T19:43:18.123 回答
0
  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();
}
于 2013-01-18T19:49:40.697 回答