在C++中将成员的引用初始化为NULL

25

在C++中是否可以将引用成员初始化为NULL?
我想尝试像这样做:

class BigClass
{
private:
    Object m_inner;
public:
    const Object& ReadOnly;
    BigClass() : ReadOnly(NULL)
    {
      Do stuff.
    }
};
我知道如果我将“ReadOnly”初始化为一个对象的实际引用,则可以做到这一点,但是当我想在那里放置“NULL”时,我会收到错误消息:“无法将'int'转换为'const Object&'”。我该怎么解决?

7
参考点的作用就是使这种情况变得不可能。使用常规指针即可。 - Hans Passant
你可以这样做: const Object& ReadOnly = \*(Object\*)NULL; 但是这样让人感到很糟糕。 预处理程序只会移除 & 和 *。 - Justin
@Justin "预处理器只是删除了&和*这些废话" - curiousguy
@curiousguy 嗯...让我解释一下,反对者。预处理器取消了 *& 组合。使用 ref & 声明只是简写,所以您不需要使用 -> , 它是 (*the).thing 的简写。就是这样;) - Justin
@Justin,C++预处理器并没有这样的功能。 - curiousguy
抱歉,预编译器。 - Justin
5个回答

42

不可以,在C++中参考(reference)不能为NULL1

可能的解决方案包括:

  • 使用指针代替参考。
  • 使用一个虚拟的Object实例来表示“没有对象”。

[1] 来自C++11标准

[dcl.ref] [...] 在一个定义良好的程序中,空引用是不存在的,因为创建这样的引用的唯一方式是将其绑定到通过解除引用空指针获得的“对象”,这会导致未定义的行为。


@Magnus:是的,不要这样做,这是未定义行为。 - Xeo
@wandalen - 哪个部分? - Oliver Charlesworth
@OliverCharlesworth 参考并不是神奇的东西。参考也可能指向 NULL。例如:Object& object = ( Object ) NULL。 - Kos
@wandalen - 这个编译不了。 - Oliver Charlesworth
上次星号被stackoverflow删除了,很抱歉。 - Kos
显示剩余3条评论

10

你无法“解决”这个问题。如果你想让该成员不指向任何东西,可以使用指针。

引用必须初始化为一个真实的对象,它们不能“指向空”。


4
@EthanSteinberg说:“这取决于情况。智能指针通常涉及所有权。有时您只想指向某个东西,而不是声明所有权。当然,您可以使用弱指针,但这需要在堆上分配对象:没有堆栈分配的对象,没有更大对象的属性等等…… 智能指针并不是万能药。” - Matthieu M.

9
可以这样做,但几乎肯定是一个极其糟糕的想法。方法是取消引用适当类型的NULL指针,这已经表明这是一个坏主意:在这一点上,您会遇到未定义的行为,但通常倾向于“工作”。
在C++中,引用始终指向实际对象。这与其他编程语言不同,在其他编程语言中,“引用”实际上相当于C++中的指针(通常没有指针算术运算)。您可能真正想要的(不幸的是,您没有说明要尝试实现什么,而是询问解决问题的解决方案,这可能是错误方法的一部分)是使用指针。
Object const* const readOnly;
BigClass(): readOnly(0) {}

我最喜欢的答案。我刚刚调试了一个复杂的类,并需要调用一个特定对象的单个函数。0引用了所有描述的引用,构造了obj,忽略了引用,调用了函数,解决了问题,撤销了所有操作。显然这不是你想永久做的事情。 - Cookie

6

它在编写单元测试时非常有用。这是唯一应该使用它的地方,但在那里,它非常有帮助。

 Bar& bar(*static_cast<Bar*>(0));
 MockClass mock; // derives from RealClass
 mock.foo(bar);

这里,我正在测试使用MockClass的代码,而不是MockClass本身。

它不是万能药,但它可以帮助。此外,如果你想要模拟“具体”的类,GoogleMock可能会成为你的好朋友。

struct Bar;
struct RealClass {
  int& x_;
  double& y_;
  RealClass(int& x, double& y) :x_(x), y_(y) {}
  virtual void foo(Bar&);
};
struct MockClass: public RealClass {
  MockClass(): RealClass(*(int*)0, *(double*)0) {}
  MOCK_METHOD1(foo, void(Bar&));
};

踩负评者:请尝试在不使用对NULL的引用的情况下进行。非常困难!如果不明显,我们旨在测试使用“RealClass”的代码,并在该“RealClass”上调用“foo()”。我们注入了“RealClass”和“Bar”实例。“MockClass”需要调用“RealClass”的构造函数,但从未需要底层数据。这是一个有效的用例,请停止踩负评。 - cdunn2001
如果你需要编写这种类型的测试,我认为你有一个严重的设计问题。 - user3160514
这不是未定义行为。它回答了问题。请踩问题,而不是答案。 - cdunn2001
这是未定义行为。(请参见https://dev59.com/eVrUa4cB1Zd3GeqPkHUT)。 - user3160514
1
感谢@cdunn2001!对于使用GTKmm进行模拟单元测试我的应用程序非常有帮助。 - user
显示剩余3条评论

3
使用指针:- const Object* pReadOnly;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接