4

我正在学习 C++ V1 中的 C++ 形式的 Thinking。我遇到了一个演示继承的示例。来了

#include <iostream>

class Instrument{
public:
    virtual void play(){
        std::cout<<"instrument::play()";
    }
};

class Wind: public Instrument{
public:
    void play(){
        std::cout<<"Wind::play()";
    }
};

void tune(Instrument& i){
    i.play();
}
int _tmain(int argc, _TCHAR* argv[])
{
    Wind flute;
    tune(flute);
    return 0;
}

Wind::play()在控制台上输出。

但是,如果我将方法“调整”更改为

void tune(Instrument i){
    i.play();
}

输出将instrument::play()

既然添加了“&”,是为了传递长笛的引用而不是副本,为什么程序输出instrument::play()而不是Wind::play()

4

5 回答 5

17

因为传递的副本具有 type Instrument,而不是 type Wind,因为Instrument是函数采用的类型。这被称为“切片”。

于 2013-10-09T18:04:40.443 回答
7

C++ 中对象表达式的多态行为由其动态类型决定。

  • 当您将类型引用附加到类型Instrument &i对象时Wind,所引用对象的动态类型将i保留。即即使i是用 type 声明的Instrument,它实际上是指一个实际的 type 对象Wind。这就是为什么i继续表现为Wind. 如果您使用指针引用某个对象,情况也是如此。

    用正式的语言来说,就是表达式的静态类型iInstrument,如果是相同的表达式是动态类型Wind。出于这个原因,i多态表现为Wind.

  • 同时,当您分配(或初始化)具有Instrument itype 值的对象时,您将创建一个独立的 typeWind独立对象。这个对象的类型是。因此,该独立副本的行为与所有多态上下文中的行为相同。iInstrumentInstrumentiInstrument

    同样,用正式语言来说,这意味着在这种情况下,表达式的静态类型动态类型i都是Instrument. 出于这个原因,i多态表现为Instrument.

在 C++ 语言中,“保留”对象的动态类型的唯一方法是使用指针或引用来引用该对象。“引用”是这里的关键词:您不创建新对象,而是 引用已经存在的对象。并且那些现有对象继续按照它们的本机类型运行。type 的对象Wind继续作为 type 的对象Wind。(请注意,这仅适用于多态行为,例如如何解析函数调用。)

但是,每当您创建对象的独立副本(而不是引用原始对象)时,该副本就会获得自己的生命,具有自己的类型和相关属性。type 的独立副本与原始对象Instrument无关。Wind它不记得它是作为Wind对象的副本而诞生的。它表现为一个Instrument.

于 2013-10-09T18:12:01.633 回答
3

这就是所谓的“切片”问题。当你复制Wind到一个Instrument它变成一个Instrument

于 2013-10-09T18:04:56.617 回答
0

void tune(Instrument i){
    i.play();
}

如果该Instrument对象创建一个新实例,则该Instrument对象将打印instrument::play

当您使用引用运算符时&,您引用了该类型的现有对象Wind

于 2013-10-09T18:08:15.143 回答
-2

调用该Instrument::play函数的原因是,当您传递一个副本时,它实际上是Instrument您传递的对象的一部分,因为您对对象进行了切片

于 2013-10-09T18:04:31.087 回答