学习C ++:多态和切片

考虑下面的例子:

#include <iostream> using namespace std; class Animal { public: virtual void makeSound() {cout << "rawr" << endl;} }; class Dog : public Animal { public: virtual void makeSound() {cout << "bark" << endl;} }; int main() { Animal animal; animal.makeSound(); Dog dog; dog.makeSound(); Animal badDog = Dog(); badDog.makeSound(); Animal* goodDog = new Dog(); goodDog->makeSound(); } 

输出是:

 rawr bark rawr bark 

但是我认为产量肯定是“ 吠叫树皮”。 badDog有什么用?


更新:您可能对我的另一个问题感兴趣。

这是一个叫“切片”的问题。

Dog()创build一个Dog对象。 如果你打电话给Dog().makeSound() ,它会打印出你所期望的“树皮”。

问题是你正在用这个Dog初始化一个types为Animal的对象badDog 。 由于Animal只能包含一只Animal而不是任何来自Animal ,因此它需要Animal一部分,并初始化自己。

badDog的types总是Animal ; 它永远不可能是别的。

你可以在C ++中获得多态行为的唯一方法是使用指针(就像你用goodDog示例演示的goodDog )或者使用引用。

参考文献(例如Animal& )可以指从Animal衍生的任何types的物体,并且指示物(例如Animal* )可以指向来自Animal的任何types的物体。 然而,一只普通的Animal总是一只Animal ,没有别的。

像Java和C#这样的语言具有引用语义,其中variables(大多数情况下)只是引用对象,所以给定一个Animal rex;rex实际上只是一些Animal的参考, rex = new Dog()使得rex指向一个新的Dog对象。

C ++不会这样工作:variables不会引用C ++中的对象,variables是对象。 如果在C ++中使用rex = Dog() ,它会将一个新的Dog对象复制到rex ,并且由于rex实际上是Animaltypes,它将被切片并且只复制Animal部分。 这些被称为值语义,这是C ++中的默认值。 如果你想在C ++中引用语义,你需要明确地使用引用或者指针(这些引用或者指针都不是C#或Java中的引用,但是它们更类似)。

  Animal badDog = Dog(); ad.makeSound(); 

当你实例化一个Dog并将它赋值给一个Animalvariables时,你可以切片该对象。 这基本上意味着你从badDog所有的badDog并且把它放到基类中。

为了在基类中使用多态,你必须使用指针或引用。

您使用赋值运算符初始化badDog。 因此Dog()被复制为Animal。 你的程序的输出是正确的。 🙂