我想制作一个派生类,该派生类可以使用std :: async调用基类方法。当我尝试执行此操作时,我收到一条编译器消息,指出它已受到保护,但是我将“ this”作为实例传递,该实例是我要执行的函数的派生类。
这是我的MCVE:
#include <iostream>
#include <thread>
#include <future>
class Base
{
protected:
bool threadFunc()
{
std::cout << "threadFunc called" << std::endl;
return true;
}
};
class Derived : public Base
{
public:
void callBaseMethodAsync()
{
std::future<bool> results = std::async(std::launch::async, &Base::threadFunc, this);
}
};
int main()
{
Derived test;
test.callBaseMethodAsync();
}
使用gcc 4.8会导致此编译器错误消息:
g++ -o source.o -c -std=c++11 source.cpp
source.cpp: In member function 'void Derived::callBaseMethodAsync()':
source.cpp:8:10: error: 'bool Base::threadFunc()' is protected
bool threadFunc()
^
source.cpp:20:75: error: within this context
std::future<bool> results = std::async(std::launch::async, &Base::threadFunc, this);
为什么std :: async使受保护的方法无法从派生类访问?使用异步从派生类中调用基类方法有哪些替代方法?
答案 0 :(得分:4)
您必须使用&Derived::threadFunc
而不是&Base::threadFunc
,因为当成员函数在基类中受保护时,您必须使用当前上下文的类。
(更新:这与我之前写的this
指针类型无关。这是胡扯。)
LLVM甚至在错误消息中说明了解决方法:
ov@abook:~/tmp>g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
ov@abook:~/tmp>g++ -std=c++11 t.cpp
t.cpp:20:75: error: 'threadFunc' is a protected member of 'Base'
std::future<bool> results = std::async(std::launch::async, &Base::threadFunc, this);
^
t.cpp:8:14: note: must name member using the type of the current context 'Derived'
bool threadFunc()
^
1 error generated.
答案 1 :(得分:2)
有一个关于受保护成员访问的特殊规则。 Derived
没有访问其基类的受保护成员的无条件能力。如果采用成员指针,则必须使用自身作为类(或Derived
的派生类),而不是Base
。标准参考是[class.protected] / 1:
当非静态数据时,将应用第14章前面所述之外的其他访问检查 成员或非静态成员函数是其命名类(14.2)的受保护成员。如前所述 较早的时候,授予访问受保护成员的权限是因为引用发生在某些朋友或成员中 类
C
。如果访问是为了形成指向成员(8.3.1)的指针,则嵌套名称说明符应表示C
或 从C
派生的类。所有其他访问都涉及一个(可能是隐式的)对象表达式(8.2.5)。在这种情况下, 对象表达式的类别应为C
或从C
派生的类别。
换句话说,您必须写&Derived::threadFunc
而不是&Base::threadFunc
。名称查找将在threadFunc
中找到Base
,但是结果指向成员的指针只能用于类型为Derived
的对象或更多派生类中。这允许Derived
对象使用threadFunc
访问属于Base
的自身内部,但是阻止其观察从Base
派生的其他类中的内部。 / p>