为什么这个虚方法 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;
在学习 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;