#include <iostream>
class Test {
public:
int i;
void print()
{
std::cout << "Hello" << std::endl;
}
};
int main()
{
class Test *p = NULL;
p->print();
(*p).print();
}
Output:
Hello
Hello
我理解对象方法和成员变量存储在内存中的不同位置,但是p
被指定为NULL
时如何解析调用Test::print()
Test6:~ 1001> g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Test6:~ 1002> g++ manoj.cpp
Test6:~ 1003> ./a.out
Hello
Hello
Test6:~ 1004> cat manoj.cpp
#include <iostream>
class Test {
public:
int i;
void print()
{
std::cout << "Hello" << std::endl;
}
};
int main()
{
class Test *p = NULL;
p->print();
(*p).print();
}
Test6:~ 1005>
答案 0 :(得分:3)
除非类具有虚函数(即编译器不创建vtable),否则所有指向方法的指针都将在程序中进行硬编码,因此不需要任何变量信息。但是,即使在这种情况下,它也没有有效的this
指针,因此它仍会崩溃。
答案 1 :(得分:0)
你根本做不到这一点。 此代码无法编译,并且您无法寻址空指针。尝试使用:
int main()
{
// no need for 'class' keyword when declaring the pointer:
Test* p = new Test(); // use default constructor provided by compiler
p->print();
(*p).print();
// you also need to delete the pointer before returning, but that's irrelevant
return 0; // you need this too
}
答案 2 :(得分:0)
你所做的不是一个“良好开发的代码片段”,但是它有效,因为即使this指针为null,你也不会(明确地或隐含地)取消引用它。
你的* p(或p->)属于Test
类,而Test::print
没有引用Test中的任何内容,所以......因为 null测试总是 Test ,你不关心它的内容,代码编译和工作。
但如果符合以下条件,此代码将遇到麻烦:
Test::print
是虚拟的:在这种情况下,p->print()
(或(*p).print()
)必须通过实际对象的v表来检测要调用的函数。 (*p
可以是Test
派生的任何内容,但由于没有对象,因此无法检测到v-table,程序将崩溃。Test
有一个成员,你的print
函数用于打印它:在这种情况下,由于p
指向一个无效的内存块,你的函数--wile访问成员变量 - 将尝试隐式取消引用null此指针以计算成员的位置。并且会导致内存地址无效,从而导致崩溃。事实上,你刚刚进入了一个名为“ undefined behavior ”的灰色区域:语言律师(编写规范的人)对此没有任何说法(特别是:从未说过) “取消引用无效指针是一个(运行时)错误”:他们说“取消引用无效指针会导致未定义的行为”,这几乎意味着“我们不想要”告诉你应该发生什么“)。
但是由于编译器编写者必须做某事(编译器不能“未定义”),因为在编译时 - 翻译一行代码 - 他们无法知道指针的值是什么,他们决定翻译任何方式的代码。
由于代码的执行不会破坏任何进程边界,因此不会崩溃。 并且由于没有访问“正在进行未初始化的空间”,因此看不到杂乱的值,一切看起来都不错。
欢迎使用非托管语言字!