通过对基类的引用调用虚函数

12

当我运行这段代码时,它拒绝向控制台打印适当的消息。使用指针而不是引用似乎有效(使用->代替.)。我是OOP新手,如果您觉得这很荒谬,请原谅我。

#include <iostream>

using namespace std;

class instrument {
public:
    virtual void play(){}
};

class drum : public instrument {
public:
    void play(){
        cout << "dum, dum" << endl;
    }
};

class piano : public instrument {
public:
    void play(){
        cout << "pling" << endl;
    }
};

int main (){
    instrument i;
    piano p;
    drum d;

    instrument &pi = i;
    pi.play();  // -

    pi = p;
    pi.play();  // pling

    pi = d;
    pi.play();  // dum, dum
}

13
初始化时绑定对象的引用是无法更改的。目前您正在触发赋值操作符(并在此过程中触发了对象切片问题)。 - WhozCraig
4
可以,先生,请允许我将其翻译为回答吗? - jrok
一个小问题,但你需要在基类中创建一个虚析构函数。 - Peter Wood
@PeterWood:也许是个好主意,但并不是必需的,因为他没有通过基类指针调用析构函数。 - Martin York
可能是重复的问题:基类引用 - 分配其他类型 - mmmmmm
3个回答

21
instrument &pi = i;

在这里,您使 pi 引用 i 对象中的 instrument

pi = p;

在这里,您将piano对象p分配给被pi引用的对象。引用pi没有重新绑定到piano对象。它仍然指向与以前相同的instrument对象。只是使用隐式生成的默认赋值运算符分配了不同的内容。 (在这种情况下,赋值没有效果,但是将派生类型分配给基类型通常会导致对象切片。)当您调用pi.play()时,引用仍然指向一个instrument对象,并执行instrument::play

关键在于,虽然您可以让指针指向不同类型的不同对象,但是您不能对引用执行相同的操作。它始终指向相同的对象。您可以通过使用多个引用来修复代码:

instrument &pi = i;
pi.play();  // -

instrument &pp = p;
pp.play();  // pling

instrument &pd = d;
pd.play();  // dum, dum

1
指针比引用更加灵活多用,是吗? - Venom
@Venom 不是的,它们各有其用。 - BЈовић
1
@Venom 如果你只考虑它们的原始功能,它们可能会更灵活。然而,你并不总是想要那种灵活性。事实上,这甚至可能导致问题。为工作选择适当的类型。 - Joseph Mansfield
1
是的,指针确实更加灵活多用。但这并不意味着它们没有用处。 - Kyle Strand

2
int main ()
{ 
    instrument i,*pi;
    piano p;
    drum d; 
    pi= &i; 
    pi->play(); // - 
    pi = &p; 
    pi->play(); // pling
    pi = &d; 
    pi->play(); // dum, dum 
}

5
欢迎来到 StackOverflow!请在您的帖子中添加解释来补充您的代码。翻译完毕,无其他返回信息。 - Kevin

1

使用:

virtual void play() = 0;

改为:

virtual void play(){}

它可以防止重复创建对象的可能性。

你能解释一下你的答案以便更好地理解吗?谢谢。 - Shanteshwar Inde

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接