学习C++:多态和切片

JnB*_*ymn 54 c++ polymorphism

请考虑以下示例:

#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();
}
Run Code Online (Sandbox Code Playgroud)

输出是:

rawr
bark
rawr
bark
Run Code Online (Sandbox Code Playgroud)

但我认为产量肯定应该是"粗树皮树皮".badDog有什么用?


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

Jam*_*lis 75

这是一个叫做"切片"的问题.

Dog()创建一个Dog对象.如果你打电话Dog().makeSound(),它会像你期望的那样打印出"树皮".

问题是你正在初始化badDog,这是一个类型的对象Animal,用它Dog.由于Animal只能包含一个Animal而不是从中派生的任何内容Animal,因此它需要Animal部分内容Dog并使用它进行初始化.

badDog总是那种类型Animal; 它永远不会是别的.

在C++中获得多态行为的唯一方法是使用指针(正如您在示例中演示的那样goodDog)或使用引用.

引用(例如,Animal&)可以指代从中派生的任何类型的对象,Animal并且指针(例如,Animal*)可以指向从中派生的任何类型的对象Animal.Animal然而,平原总是一个Animal,没有别的.

像Java和C#有些语言有引用语义,其中变量(在大多数情况下)只是对象的引用,所以给出的Animal rex;,rex实际上只是一些参考Animal,并rex = new Dog()rex指新Dog对象.

C++不能这样工作:变量不引用C++中的对象,变量是对象.如果你rex = Dog()在C++中说它会复制一个新Dog对象rex,并且因为rex实际上是类型Animal,它会被切片并且只是Animal部分被复制.这些被称为值语义,它是C++中的默认值.如果你想在C++中使用引用语义,你需要显式地使用引用或指针(这两者都不同于C#或Java中的引用,但它们更相似).

  • 我将补充一点,我粗略地简化了Java与C#和C++类型系统之间的比较. (5认同)

Joh*_*ing 11

 Animal badDog = Dog();
    ad.makeSound();
Run Code Online (Sandbox Code Playgroud)

实例化a Dog并将其按值分配给Animal变量时,可以对对象进行切片.这基本上意味着您将所有Dog-ness从中删除badDog并进入基类.

为了将多态性与基类一起使用,必须使用指针或引用.