C ++ 11类,指针和全局范围声明的奇怪行为

时间:2015-02-10 13:32:04

标签: c++ class pointers c++11

[Global Scope]

myClass *objA, *objB, *obj;
int objnum;

我想在objAobjB之间切换,并将其替换为obj,因此在main()我有:

int main()
{
  objA = new myClass(parameters...);
  objB = new myClass(parameters...);

  // start with objA;
  objnum = 0;
  obj = objA;
}

在某些时候调用一个在两个对象之间切换的函数:

void switchObjects()
{
  if (++objnum > 1) objnum = 0;
  obj = objnum == 0 ? objA : objB;
}

在我使用该对象的函数中,我有:

void doYourJob()
{
  int res = obj->work();
}

现在奇怪的是,如果我不将obj分配给objAobjB,它仍然有效。相反,我会期待一个例外。即使我做obj = NULL;,它仍然有效!什么是这个伏都教?

好的,我可以提供一个不同的示例,它会带来相同的结果,而不使用NULL指针:

myClass *obj[2];
int objnum;

void switchObject()
{
  if (++objnum > 1) objnum = 0;
}

void doYourJob()
{
  res = obj[objnum]->work();
}

int main()
{
  obj[0] = new myClass(parameters...);
  obj[1] = new myClass(parameters...);

  objnum = 0;
}

使用上面的代码,无论objnum的值如何,我仍然可以让两个对象一起工作,即使我只在一个实例上调用work()

如果我用这个替换函数doYourJob()

void doYourJob()
{
  int res1 = obj[0]->work();
  int res2 = obj[1]->work();
}

我总是将结果加倍,好像我在每个对象上调用函数work()两次。

1 个答案:

答案 0 :(得分:4)

考虑一个更简单的例子:

#include <iostream>

struct X
{
    void foo() { std::cout << "Works" << std::endl; }
};

int main() {
    X* x = nullptr;
    x->foo();
}

对于大多数编译器和大多数平台,尽管在空指针上调用foo,但此代码似乎仍能正常工作。但是,该行为在技术上是 undefined 。也就是说,C ++语言对于执行此操作可能会发生的情况没有任何限制。

为什么会这样?好吧,调用成员函数只需要知道它被调用的对象的类型。我们知道x指向X,因此我们知道要调用的函数:X::foo。在许多情况下,可能很难甚至不可能知道指针是否指向真实对象,因此编译器只是让它发生。在这种情况下,函数体实际上并不依赖于实际存在的X对象,因此它只是起作用。这不是你可以依赖的东西。