2

我正在尝试使用boost::bind调用类中的成员函数。通常这可以正常工作,但在这种特殊情况下,我的编译器 (GCC) 抱怨我在尝试使用不可访问的基类,而我不是。

这是一些演示问题的代码。我究竟做错了什么?

#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>

class base
{
    protected:
        void test()
        {
            std::cout << "base::test()\n";
        }
};

class derived: virtual protected base
{
    public:
        using base::test;
};

int main(void)
{
    derived d;

    // This works, calling derived::test(), which in turn calls base::test()
    d.test();

    // This does not work, saying 'base' is an inaccessible base of 'derived',
    // but I am not binding base::test, I am binding derived::test.
    boost::function<void()> fn;
    fn = boost::bind(&derived::test, d);
    fn();

    return 0;
}
4

2 回答 2

7

using声明没有定义函数。它“声明一个名称”(不是一个函数!),并取消隐藏基本名称。确实,声明本身有自己的可访问性级别,这就是为什么您首先要使用它的原因,但要再次强调:using 声明没有声明新的成员函数。例如 C++11 7.3.3/11:

由using-declaration 声明的实体应根据 using-declaration 处的定义在使用它的上下文中为人所知。

在您的情况下,“它的定义”仍然是void base::test(){},并且派生类已知并由 引用的实体&derived::test。您无法从中获取类型的函数指针,void(derived:**)()因为没有这样的函数。

当您说&derived::test时,使用&-operator,其工作方式如下(5.3.1/3):

一元运算符的结果&是指向其操作数的指针。操作数应该是一个左值或一个qualified-id。如果操作数是一个限定id,m命名某个类的非静态成员,C类型为T,则结果的类型为“指向类型成员的指针CT,并且是一个指定C::m 的prvalue。

在我对上述逻辑的解释中, “命名类&derived::test的非静态成员”。[感谢@DyP:] 在 10.2/3 中正式化:testbase

f[...]中的查找集C由 [...] 声明集 [...] 组成。在声明集中,使用声明被它们指定的成员替换

如果你真的想要,你可以提供一个这样的包装器:

class derived : protected base
{
public:
    void test() { base::test(); }
};

(奇怪的是,该解决方案实际上确实隐藏了我们想要的基函数。我们不使用using,而是使用显式限定名称来引用基函数。)

于 2013-10-12T23:25:08.517 回答
6

调用函数时,需要将隐式this参数转换为基类。该using声明不会调整testfrombase::*到的类型derived::*

您可以手动执行此类调整:

static_cast< void (derived::*)() >( &derived::test )

但这同样要求基地是可访问的。因此,完整的解决方案是将上述内容封装在static_cast派生类中。否则它应该是一个可访问的基础。

于 2013-10-13T01:08:40.983 回答