学习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。 你的程序的输出是正确的。 🙂