为什么使用声明不公开指向成员的指针
Why does using declaration not expose pointer to member
考虑:
struct foo
{
void foobar(){}
};
struct bar : protected foo
{
using foo::foobar;
};
int main()
{
bar b;
b.foobar(); // Fine
&bar::foobar; // Not fine
}
我想知道让使用声明公开成员,而不是指向它的指针的理由是什么。事实上,似乎所有更改访问级别的使用声明都适用于除获取公开函数地址之外的所有内容。
UPDATE:一个更像我真实用例的例子:
#include "boost/bind.hpp"
struct foo
{
void foobar() {}
};
struct bar : protected foo
{
using foo::foobar;
bar() { boost::bind( &bar::foobar, this )(); } // Crashes VS2008, GCC 4.1.1 fails to compile as it tries to go through foo*
};
int main()
{
bar b;
}
然而,Mike Seymours的解释很到位,解释了GCC失败的原因。谢谢
[我假设在您的程序中,代码是:void (bar::*p)() = &bar::foobar;
]
问题不在于using声明没有将标识符带入空间,而在于&bar::foobar
的语义。我正在考虑(如果我有时间的话,我会这么做的)用这个重新填充缺陷报告。已经有一份这样的报告。
基本上,问题是using声明将基函数带入派生类型中的查找范围,并且将对照bar
检查表达式&bar::foobar
的访问说明符但是,表达式&bar::foobar
的结果是类型void (foo::*)()
,而不是void (bar::*)()
。现在,在评估&bar::foobar
之后,如果您尝试将其用作void (bar::*)()
,编译器将尝试执行指向成员的指针的转换,但会失败,因为foo
是bar
的protected
基,并且在main
的上下文中,您无法访问该关系。
请注意,我认为这是该语言的一个缺陷,原因有两个:首先,它破坏了您的代码:void (bar::*p)() = &bar::foobar;
出人意料地无法编译。其次,它在其他情况下破坏了访问保护:
class base {
protected: void f() {}
};
struct derived : base {
void foo( base& b ) {
b.f(); // Error
b.*(&derived::f)(); // OK
}
};
这个问题实际上与您的问题是对称的,而在您的问题中,成员操作的地址这一令人惊讶的类型会在不应该使用的情况下抑制您的用例,在这种情况下,它允许违背protected
意图的使用。
相关链接:
- DR 203-成员表达式的地址类型
- DR 1007-受保护的访问和指向成员的指针
在对使用bind
发表评论后,您可能不会试图将指向成员的指针直接转换为指向bar
成员的指针,但bind
内部的某个地方会生成代码,将指向成员指针应用于bar
的实例,这需要转换。
注意:这回答了最初的问题;David Rodriguez已经回答了最新消息。
你的代码很好。根据语言标准:
7.3.3/2每个使用声明都是声明员声明
这意味着您将foobar
声明为bar
和foo
的成员,因此将其称为bar::foobar
与foo::foobar
一样合法。
我的编译器(GCC)同意这一点;如果你的没有,那么它似乎有一个bug。
- 从成员指针到整个结构/类的强制转换
- OOP 中的单成员指针
- 使用结构成员指针在C++中填充结构
- 聚合初始化,将成员指针设置为同一结构成员
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 共享 C++ 的数据成员指针
- 如何声明指向成员内容的成员指针m_pmd/m_pmf并访问它们?
- 从类C++外部调用指向成员方法的成员指针
- 结构成员指针是否自动初始化为零?
- 如何删除类内类类型的类成员指针
- 是否打印指向已定义 int 的成员指针
- 指向常量的成员指针
- 通过此指针访问时的成员差异和自身的成员指针(简单的 QT 示例问题)
- 类数据成员指针的非类型模板参数包无法使用 gcc 编译
- 为什么我不能在同一行中定义两个相同类型的类的成员指针
- 将类成员指针传递给 Lambda 捕获列表 c++11
- 在单一实例类中将成员指针设置为 null 的正确方法是什么
- 无法删除在destructor中的成员指针的课程
- 删除对象而不调用成员指针的析构函数
- 当派生类的基类具有成员指针时,对其进行深层复制