0
#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>
4

3 回答 3

3

Unless a class has virtual functions(i.e. compiler does not create vtable), all the pointers to the methods will be hardcoded in the program, thus not requiring any of the variable information. However, even in that case, it would not have a valid this pointer, so it will still crash.

于 2011-11-17T05:14:19.897 回答
0

You simply cannot do this. This code wouldn't compile, and you cannot address a null pointer. Try using:

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
}
于 2011-11-17T05:14:38.217 回答
0

您所做的不是“开发良好的代码”,但它可以工作,因为即使 this 指针为空,您也从未(显式或隐式)取消引用它。

您的 *p (或 p->)属于 class Test,并且Test::print不引用 Test 内部的任何内容,所以......因为null Test始终是Test并且您不关心它的内容,所以代码编译并工作.

但是如果出现以下情况,这段代码会遇到麻烦:

  • Test::print被做成虚拟的:在这种情况下p->print()(或(*p).print())必须通过实际对象的 v-table 来检测调用哪个函数。(*p可以是任何Test-派生的),但是由于没有对象,因此无法检测到v-table,并且程序将崩溃。
  • Test被制作成有一个成员,并且你的print函数被打印出来:在这种情况下,由于p指向一个无效的内存块,你的函数 - 访问成员变量 - 将尝试隐式取消引用 null this 指针来计算成员的位置是。并且会导致内存地址无效,从而导致崩溃。

实际上,您刚刚进入了称为“未定义行为”的灰色区域:语言律师(编写规范的人)对此没有说任何话(特别是:从未说过“取消引用是(运行时)错误一个无效的指针“:他们说“取消引用一个无效的指针会导致未定义的行为”,这几乎意味着“我们不想告诉你应该发生什么”)。

但是由于编译器编写者必须做一些事情(编译器不能“未定义”),因为在编译时 - 在翻译一行代码时 - 他们不知道指针的值是什么,他们决定将代码翻译成任何方法。

而且由于代码的执行不会破坏任何进程边界,因此不会崩溃。而且由于没有访问“进程中未初始化的空间”,因此看不到杂乱的值并且一切看起来都很好。

欢迎使用非托管语言一词!

于 2011-11-17T07:39:14.430 回答