指向成员的引用指针是否合法?

22

假设有这样一个情况:

// This is all valid in C++11.
struct Foo {
    int i = 42;
    int& j = i;
};

// Let's take a pointer to the member "j".
auto b = &Foo::j; // Compiler is not happy here
// Note that if I tried to get a pointer to member "i", it would work, as expected.
Foo f;
std::cout << f.*b; // Try using the pointer to member

编译器报错说我不能取成员的地址,因为它是一个引用。确切地说:

语义问题:无法形成指向引用类型“int&”的成员“j”的指针

我知道这样做似乎毫无意义,但我只是想知道为什么不能这样做。

为什么这是不可能的?


@SethCarnegie:我是说Foo,抱歉。 :) - fronsacqc
@PrasoonSaurav b 是一个成员指针,而不是成员。注意到了 .* 吗? - fronsacqc
1
@Doug:这就是问题所在。为什么这不是有效的C++代码? - Benjamin Lindley
你可以始终使用引用包装器。你可以创建指向它们的指针。 - Pubby
4个回答

14

这是不可能的,因为你无法获取引用的指针- 没有任何例外。

如果您可以获取一个成员指针来引用,这将与堆栈上引用的行为不一致。C++的态度是引用不存在。因此,您永远不能形成对它们的指针。

例如,&f::a必须与&f::b不同。通过对&f::b进行取消引用,您实际上正在获得指向引用的指针,这是不允许的。


@DeadMG: "堆栈上引用的行为"是什么意思? - fronsacqc
但我经常使用&my_vector[0] - 而且我确信operator[]返回一个引用。 - Mark Ransom
1
如果你获取了一个指向栈上的int&的指针,你会得到一个int*。然而,通过获得一个指向成员引用的指针,你实际上是绕过了这个问题,实现了指向引用的指针。&f::a必须与&f::b不同,但这是不允许的,因为引用不是对象。 - Puppy
1
@MarkRansom:这不会产生指向引用的指针,它会产生指向被引用对象的指针。两者是不同的东西。 - Puppy
2
@MarkRansom:你可以取一个引用的地址,这个地址是引用对象的地址。但你不能直接指向一个引用本身。 - GManNickG
显示剩余2条评论

14

C++11标准:

§8.3.3 p3 [dcl.mptr]
成员指针不得指向类的静态成员(9.4)、引用类型的成员或“cv void”。

此外,在一般情况下:

§8.3.1 p4 [dcl.ptr]
[注:没有指向引用的指针;参见8.3.2。[...] —end note]

§8.3.2 p5 [dcl.ref]
不允许存在对引用的引用,不允许有数组存储引用,也不允许有指向引用的指针


1
我想知道为什么标准反对它。我很想知道原因。 - fronsacqc
@fronsacqc:那么,你将不得不发送标准委员会的邮件列表comp.lang.c++.moderated,或者希望Howard Hinnant(委员会成员在SO上漫游)回答这个问题。 - Xeo
3
因为指针指向对象,但引用不是对象。 - fredoverflow
@Fred:好观点,等我下班回来后,我会编辑这个答案,包括支持标准引号的内容。至少应该是可行的。 :) - Xeo

7

成员指针(与简单指向成员的指针相对)只是指向结构体中的一个偏移量,根本就不是指针。你只能在结构体本身(或指向结构体的指针)的帮助下获取数据:将偏移量的值加到结构体的地址上,并解引用以产生成员的值。

现在假设成员是一个引用,因此通过它访问数据已经需要解引用(编译器会向我们隐藏此过程,但它需要在输出中输出相应的指令)。如果C++允许成员指针指向引用,它们将成为另一种类型:需要将偏移量添加到基础地址,然后再进行两次解引用。这样做多余且复杂,禁止它是更好的出路。


@R.MartinhoFernandes 嗯,那是成员函数指针。数据成员的指针要简单得多,因为数据成员不能是虚拟的。 - Sergey Kalinichenko
谢谢,这是我迄今为止得到的最佳答案。它解释了为什么不支持该功能,因此我并不是期望它能正常工作的疯子。这只意味着它不被支持。 - fronsacqc
2
@fronsacqc 当然可以实现这个功能,只要你将其嵌入到某种有意义的语义中。不幸的是,对于像这样的晦涩功能,这样做属于问题领域,而不是解决方案。幸运的是,标准化委员会中的某些人早就认识到了它的问题,并在它成为问题之前禁止了该功能。 - Sergey Kalinichenko

1

允许您创建指向引用的指针并不会给您带来任何表达能力。您无法使用这种“野兽”做任何您不能轻松使用引用或指针完成的事情。您从中得到的只是增加了复杂性。

而且,为了与禁止指向引用的规则保持一致,并且因为它增加了更多的复杂性,所以不允许创建指向成员的指针。语言设计者可能认为,从中获得的小收益不值得。

这完全只是我的个人意见。


你不能同时声称它不给你任何表现力,但又声称指向引用成员的指针只有“少量”收益。如果B是有用的,而A允许B,则A在某些方面也必须是有用的。 - Eric

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