我正在尝试使用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;
}
答案 0 :(得分:7)
using
声明未定义函数。它“声明一个名称”(不是函数!),并取消隐藏基本名称。确实,声明本身具有自己的可访问性级别,这就是您首先使用它的原因,但再次强调:using声明不会声明新的成员函数。例如。 C ++ 11 7.3.3 / 11:
using-declaration 声明的实体应在上下文中根据using-declaration点的定义使用它。
“它的定义”,在您的情况下,仍为void base::test(){}
,而 是派生类已知并由&derived::test
引用的实体。你不能从中获得类型void(derived:**)()
的函数指针,因为没有这样的函数。
当您说&derived::test
时,会使用&
- 运算符,其工作原理如下(5.3.1 / 3):
一元
&
运算符的结果是指向其操作数的指针。操作数应为左值或 qualified-id 。如果操作数是 qualified-id ,则命名类型为m
的某个类C
的非静态成员T
,结果的类型为“指向成员的指针C
类的T
类,并且是指定C :: m的prvalue。
在我对上述逻辑的解释中,&derived::test
“命名类test
的非静态成员base
”。 [感谢@DyP:]在10.2 / 3中正式化:
f
[...]中C
的查找集包含[...]声明集[...]。在声明集中, using-declarations 由他们指定的成员替换
如果你真的想要,你可以提供这样的包装:
class derived : protected base
{
public:
void test() { base::test(); }
};
(奇怪的是,该解决方案实际上 隐藏了基本功能,这是我们想要的。我们使用显式限定名称来引用基本功能,而不是使用using
。 )
答案 1 :(得分:6)
调用函数时,需要将隐式this
参数转换为基类。 using
声明不会将test
的类型从base::*
调整为derived::*
。
您可以手动执行此类调整:
static_cast< void (derived::*)() >( &derived::test )
但这同样要求基地可以访问。因此,完整的解决方案是将上述static_cast
封装在派生类中。否则它应该是一个可访问的基础。