学习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
实际上是Animal
types,它将被切片并且只复制Animal
部分。 这些被称为值语义,这是C ++中的默认值。 如果你想在C ++中引用语义,你需要明确地使用引用或者指针(这些引用或者指针都不是C#或Java中的引用,但是它们更类似)。
Animal badDog = Dog(); ad.makeSound();
当你实例化一个Dog
并将它赋值给一个Animal
variables时,你可以切片该对象。 这基本上意味着你从badDog
所有的badDog
并且把它放到基类中。
为了在基类中使用多态,你必须使用指针或引用。
您使用赋值运算符初始化badDog。 因此Dog()被复制为Animal。 你的程序的输出是正确的。 🙂