考虑:
struct foo
{
void foobar(){}
};
struct bar : protected foo
{
using foo::foobar;
};
int main()
{
bar b;
b.foobar(); // Fine
&bar::foobar; // Not fine
}
我想知道让使用声明暴露成员的理由是什么,而不是指向它的指针。实际上,除了获取公开函数的地址之外,似乎所有使用声明都会更改访问级别的所有内容。
更新:更好地类似于我的实际用例的示例:
#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失败的原因。谢谢!
答案 0 :(得分:6)
[我假设您的程序代码为:void (bar::*p)() = &bar::foobar;
]
问题不在于 using声明不会将标识符带入空间,而是&bar::foobar
的语义。我正在考虑(如果我有时间,我会这样做)用这个填写缺陷报告。已有一份此类报告。
基本上问题是using声明将基本函数带入派生类型中的查找范围,并且将针对&bar::foobar
检查表达式bar
的访问说明符。 但,表达式&bar::foobar
的结果属于void (foo::*)()
,而非void (bar::*)()
。现在,在评估&bar::foobar
之后,如果您尝试将其用作void (bar::*)()
,编译器将尝试执行指向成员的指针转换,但会失败,因为foo
是{{1} } protected
的基础,并且在bar
的上下文中,您无权访问该关系。
请注意,我认为这是语言中的缺陷有两个原因:首先它会破坏您的代码:main
令人惊讶地无法编译。其次,它在其他情况下打破了访问保护:
void (bar::*p)() = &bar::foobar;
这个问题实际上与你的问题是对称的,而在你的问题中,令人惊讶的成员地址操作类型会在不应该的情况下禁止你的用例,在这种情况下它会允许使用违反{{{ 1}}。
相关链接:
在使用class base {
protected: void f() {}
};
struct derived : base {
void foo( base& b ) {
b.f(); // Error
b.*(&derived::f)(); // OK
}
};
的注释之后,可能不是您尝试将指向成员的指针直接转换为指向protected
成员的指针,而是在bind
内的某处将生成代码以将指向成员的指针应用于bar
的实例,这需要转换。
答案 1 :(得分:3)
注意:这回答了原始问题; David Rodriguez已回复此更新。
你的代码很好。根据语言标准:
7.3.3 / 2每个 using-declaration 是声明和成员声明
这意味着您宣布foobar
成为bar
以及foo
的成员,因此将其称为bar::foobar
与{foo::foobar
一样合法1}}。
我的编译器(GCC)同意这一点;如果你没有,那么它似乎有一个错误。