2012-08-22 56 views
3

考虑做:为什么使用声明没有公开成员指针

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; 
} 

然而,迈克Seymours'的解释是现货上,并解释了为什么GCC失败。谢谢!

+4

确定吗? http://ideone.com/HbRik –

+0

@PaulManta - 可能只是VS2008然后,会做一些进一步的调查。 – Ylisar

+1

也许你可以提到你在问题的主体中使用了哪个编译器?除了提供信息外,它还能让我删除我的downvote。 – juanchopanza

回答

6

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

的问题不在于使用声明不带标识送入太空,但&bar::foobar语义。我正在考虑(如果我有时间,我会这样做)用这个补充缺陷报告。已经有一个这样的报告。

基本上问题在于使用声明将基本函数带入派生类型中的查找范围,并且将根据bar检查表达式&bar::foobar的访问说明符。 但是,表达式&bar::foobar的结果是void (foo::*)()类型,而不是void (bar::*)()。现在,&bar::foobar评估后,如果您尝试使用它作为void (bar::*)()编译器将尝试执行指针转化为成员,但会失败,因为foobar一个protected基地,并在main情况下你不有机会获得这种关系。

请注意,由于两个原因,我认为这是一种语言缺陷:首先它会破坏您的代码:void (bar::*p)() = &bar::foobar;令人惊讶地无法编译。其次,它打破在其他情况下访问保护:

这个问题实际上是对称你的,而在你的令人惊讶的类型成员地址的最运行的抑制你的使用情况,当它不应该,在这种情况下,它允许违反protected意图的用法。

相关链接:


使用bind的评论后,它可能不是你尝试指针转换为成员的情况下直接指向bar的成员,但在bind代码内的某处会生成代码将指向成员的指针应用于bar的实例,并且需要进行转换。

3

注:本回答了原来的问题;大卫罗德里格斯已经回答了更新。

你的代码是正确的。根据语言标准:

7.3.3/2每使用声明声明成员声明

这意味着你正在申报foobar是一个bar以及foo的成员,因此将其称为bar::foobarfoo::foobar一样合法。

我的编译器(GCC)同意这一点;如果你的不是,那么它似乎有一个错误。

+2

我想他错误地从问题中删除了一点。 void(bar :: * p)()=&bar :: foobar;'不会编译。 –

+0

nitpick:使用声明是类x中的成员声明不会声明类x的成员。 –