以下代码正确编译并获得神秘的输出:
特殊投资功能 00000000
(环境:C ++ VS2010)
#include <iostream>
#include <vector>
using namespace std;
class Security {
public:
virtual ~Security() {}
};
class Stock : public Security {};
class Investment : public Security {
public:
void special() {
cout << "special Investment function" << endl;
}
};
int main() {
Security* p = new Stock;
dynamic_cast<Investment*>(p)->special();
cout << dynamic_cast<Investment*>(p) << endl;
return 0;
}
怎么可能?取消引用NULL指针并获得“正确”输出而不是崩溃? 它是VS2010的特殊“特征”吗?
现在我明白了。我做了一个测试,似乎在“特殊”功能中解除引用“this”会导致程序崩溃。
感谢您的帮助。
答案 0 :(得分:7)
取消引用空指针是未定义的行为 - 您可能会得到意外的结果。请参阅this very similar question。
在这种情况下,Investment::special()
以非虚方式调用,因此您可以认为编译器只是创建了一个全局函数
Investment_special_impl( Investment* this )
并调用它将null this
指针作为隐式参数传递。
你不应该依赖于此。
答案 1 :(得分:4)
这是'未定义的bahviour'。将方法视为具有隐含参数,带有'this'。在您的情况下,NULL被作为'this'的实际参数传递。由于您没有引用“this”引用的任何对象数据(隐式或显式),因此它没有崩溃。
如果该方法是虚拟的,它很可能已经崩溃,因为虚拟调用通常通过与该对象关联的查找表进行调度(因此'this')。
由于编译器编写者可以随意实现“this”和虚拟成员查找表,因此您不应该依赖于此行为。这是未定义的。
答案 2 :(得分:2)
在大多数C ++实现中,非虚方法不需要调用有效实例(不检查this
会更快,因为标准不需要它)。
您可以将指针设置为NULL,如果您不访问实例字段,方法仍然会成功。
虚方法需要有效vtable
,因此它们总是取消引用对象并在未初始化时导致错误。
答案 3 :(得分:2)
在这里,你无处取消引用空指针:你只需要调用函数Investment :: special(NULL),它是非虚拟的,并且在它的主体中不会取消引用它。尽管规范可能告诉我这是未定义的行为,但是编译器完全理解为不在此处进行任何解除引用,因此程序不会崩溃。
答案 4 :(得分:1)
解除引用 任何 NULL指针是Undefined Behaivor。
答案 5 :(得分:1)
您不应该取消引用NULL指针,因为它可能导致Undefine Behavior。为什么你的代码有效是因为在方法中:
void special() {
cout << "special Investment function" << endl;
}
你真的没有提到this
。要进行演示,只需在Investment
类中声明一个变量,然后尝试在special()
内打印它。你会崩溃。
答案 6 :(得分:0)
取消引用空指针会调用未定义的行为,无论您是如何获得空指针,无论是dynamic_cast
还是其他内容。
答案 7 :(得分:0)
我不确定取消引用NULL问题,但我可以解释代码的行为。
<强>的dynamic_cast&LT;投资*&gt;(p) - &gt; special();
打印:“特殊投资功能”
cout&lt;&lt; dynamic_cast&lt;投资*&gt;(p)&lt;&lt; ENDL; 强>
打印:“0xABABABA”&lt; - 实例p的内存地址
就像跑步一样:
cout&lt;&lt; p <&lt; ENDL;