为什么这个虚方法 return 为真?

Why does this virtual method return true?

在学习 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() return false 吗?

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

第二个:

C& c = si;

c 以多态方式访问,因此只有动态类型才算数。 c的动态类型是See,所以选择See::has_eyesight.

第三个:

    c = Classes::c;

它不是重新绑定引用,而是将 Classes::c 复制到 c 本身。引用无法反弹。

让我们来看看你在这里做什么。

C& c = si;

c 现在是对 Classes::si 的引用,它是 See 的一个实例。所以它的 vtable 指向 See 的 vtable,has_eyesight() 将 return 为真。

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

c = Classes::c;

这不会更改对 Classes::c 的引用。您不能修改参考。相反,它调用 c 上的赋值运算符,所以现在您正在复制 Classes::c 而不是 Classes::si。除非您超载 operator=,否则这将执行逐个成员的复制。它不会修改 vtable,所以 has_eyesight() 将继续 return 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;

试试这个。

代码

c = Classes::c;

没有重新分配引用。在 C++ 中重新分配引用是不可能的。相反,它会为基础值赋值。

c = Classes::c;

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

Classes::si = Classes::c;

这不会改变 si 的虚拟 table。因此,当您使用

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