学习 C++:多态性和切片

Posted

技术标签:

【中文标题】学习 C++:多态性和切片【英文标题】:Learning C++: polymorphism and slicing 【发布时间】:2010-12-09 22:19:49 【问题描述】:

考虑以下示例:

#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

但我认为输出肯定应该是“rawr bark bark bark”。坏狗怎么了?


更新:你可能对another question of mine感兴趣。

【问题讨论】:

我认为你的变量有一些命名错误。 代码甚至无法按原样编译。还有void main() ???呃... 我不明白为什么有人会否决这个问题——这既不是“不清楚”也不是“没用”。 +1 否决反对票。 指南“使非叶类抽象”可以防止这种意外。 另一个 +1 用于发布一个完整的、最小的示例来说明问题。这正是我们一直要求的。 【参考方案1】:

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

Dog() 创建一个 Dog 对象。如果你打电话给Dog().makeSound(),它会像你期望的那样打印“bark”。

问题是您正在使用Dog 初始化badDog,它是Animal 类型的对象。由于Animal 只能包含Animal 而不能包含从Animal 派生的任何内容,因此它采用DogAnimal 部分并用它初始化自身。

badDog 的类型始终为Animal;它永远不会是其他任何东西。

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

引用(例如,Animal&amp;)可以引用从Animal 派生的任何类型的对象,而指针(例如,Animal*)可以指向从Animal 派生的任何类型的对象。但是,普通的 Animal 始终是 Animal,仅此而已。

Java 和 C# 等一些语言具有引用语义,其中变量(在大多数情况下)只是对对象的引用,因此给定 Animal rex;rex 实际上只是对某些 Animal 和 @987654344 的引用@ 使 rex 引用一个新的 Dog 对象。

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

【讨论】:

很好的解释。谢谢! 我要补充一点,我将 Java 与 C# 和 C++ 的类型系统之间的比较过分简化了。 为什么 c++ 对象赋值不复制 vptr 和其余成员,以获得变量级别的多态性?【参考方案2】:
 Animal badDog = Dog();
    ad.makeSound();

当您实例化 Dog 并将其按值分配给 Animal 变量时,您将 slice 对象。这基本上意味着您从badDog 中剥离所有Dog-ness 并将其放入基类中。

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

【讨论】:

【参考方案3】:

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

【讨论】:

以上是关于学习 C++:多态性和切片的主要内容,如果未能解决你的问题,请参考以下文章

C++继承多态总结

C++学习摘要之四:虚函数和多态

c++复习笔记——多态详细解析,多态的原理,多态的笔试题

继承与多态C++:继承中的赋值兼容规则,子类的成员函数,虚函数(重写),多态

对象切片(object slicing)和多态

学习:类和对象——多态