请考虑以下示例:
#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中的引用,但它们更相似).
Joh*_*ing 11
Animal badDog = Dog();
ad.makeSound();
Run Code Online (Sandbox Code Playgroud)
实例化a Dog
并将其按值分配给Animal
变量时,可以对对象进行切片.这基本上意味着您将所有Dog
-ness从中删除badDog
并进入基类.
为了将多态性与基类一起使用,必须使用指针或引用.