为什么使用声明不会将指针暴露给成员

Yli*_*sar 3 c++ visual-studio-2008

考虑:

struct foo
{
    void foobar(){}
};

struct bar : protected foo
{
    using foo::foobar;
};

int main()
{
    bar b;
    b.foobar(); // Fine
    &bar::foobar; // Not fine
}
Run Code Online (Sandbox Code Playgroud)

我想知道让使用声明暴露成员的理由是什么,而不是指向它的指针.实际上,除了获取公开函数的地址之外,似乎所有使用声明都会更改访问级别.

更新:一个更像我的真实用例的例子:

#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;
}
Run Code Online (Sandbox Code Playgroud)

然而,Mike Seymours的解释是正确的,并解释了GCC失败的原因.谢谢!

Dav*_*eas 6

[我假设你的程序代码是:void (bar::*p)() = &bar::foobar;]

问题不在于using声明不会将标识符带入空间,而是使用语义&bar::foobar.我正在考虑(如果我有时间,我会这样做)用这个填写缺陷报告.已有一份此类报告.

基本上问题是using声明将基本函数放入派生类型中查找的范围,并且&bar::foobar将检查表达式的访问说明符bar.但是,表达式的结果&bar::foobar是类型void (foo::*)(),而不是void (bar::*)().现在,在评估&bar::foobar您是否尝试使用它之后,void (bar::*)()编译器将尝试执行指向成员的指针的转换,但是会失败,因为foo它是protected基础bar,并且在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
   }
};
Run Code Online (Sandbox Code Playgroud)

这个问题实际上与你的问题是对称的,而在你的问题中,令人惊讶的成员地址操作类型会在不应该使用的情况下禁止你的用例,在这种情况下它会允许使用违背意图的用法protected.

相关链接:


在使用注释之后bind,可能不是您尝试将指向成员的指针转换为指向直接成员的指针的情况bar,但是在bind代码内部将生成将指针应用于成员的实例bar,并且需要转换.