为什么这个虚方法返回true?

时间:2015-07-17 22:10:05

标签: c++ reference polymorphism virtual

在C ++中学习多态性的教程时,我的一些代码似乎在调用非重写虚拟方法时表现得很奇怪。以下是课程:

// classes.cpp

namespace Classes
{
    class C
    {
    public:
        virtual bool has_eyesight()
        {
            return false;
        }
    } c;

    class See : public C
    {
    public:
        bool has_eyesight() override
        {
            return true;
        }
    } si;
}

以下是主要方法:

// file.cpp

#include <iostream>
#include "classes.cpp"

using std::cout;
using std::endl;
using Classes::C;
using Classes::See;

int main()
{
    See& si = Classes::si;

    cout << si.has_eyesight() << endl;

    C& c = si;

    cout << c.has_eyesight() << endl;

    c = Classes::c;

    cout << c.has_eyesight() << endl;
}

此代码在运行时将打印1 1 1(true true true);如果引用C而不是See?

c.has_eyesight()不应返回false

(请原谅我,如果这听起来很幼稚,我刚开始学习C ++。)

4 个答案:

答案 0 :(得分:7)

让我们来看看你在这里做的事情。

<ScrollViewer ZoomMode="Enabled" HorizontalScrollBarVisibility="Auto">
    <Image x:Name="ImgFoto" Stretch="Uniform"></Image>
</ScrollViewer>

C& c = si; 现在是对c的引用,Classes::siSee的一个实例。所以它的vtable指向See的vtable,而has_eyesight()将返回true。

引用和指针之间的主要区别在于您无法修改其目标 - c现在始终指向Classes::si,无论您做什么。含义...

c = Classes::c;

这不会更改对Classes::c的引用。您无法修改参考。相反,它会调用c上的赋值运算符,因此现在您将Classes::c复制到Classes::si上。除非您重载operator=,否则这将执行逐个成员的副本。它不会修改vtable,因此has_eyesight()将继续返回true。

如果你想让它指向别的东西,你将不得不使用指针:

See* si = &Classes::si;
cout << si->has_eyesight() << endl;
C* c = si;
cout << c->has_eyesight() << endl;
c = &Classes::c;
cout << c->has_eyesight() << endl;

试试这个。

答案 1 :(得分:2)

代码

c = Classes::c;

未重新分配参考。在c ++中无法重新分配引用。相反,它会为基础值进行分配。

答案 2 :(得分:1)

对于第二个:

C& c = si;

c以多态方式访问,因此只有动态类型计数。动态类型cSee,因此会选择See::has_eyesight

第三个:

    c = Classes::c;

它不是重新引用引用,而是将Classes::c复制到c本身。参考不能反弹。

答案 3 :(得分:1)

该行

c = Classes::c;

不要将c更改为引用Classes::c。相反,该行等同于:

Classes::si = Classes::c;

这不会更改si的虚拟表格。因此,当您使用

时,您将继续执行Classes::See::has_eyesight()
cout << c.has_eyesight() << endl;