c++ - 公共(public)访问声明不影响成员函数指针?

标签 c++ inheritance language-lawyer

我对 g++(5.1 版)下的访问声明有疑问。

class Base
{
public:
    void doStuff() {}
};

class Derived : private Base
{
public:
    // Using older access declaration (without using) shoots a warning
    // and results in the same compilation error
    using Base::doStuff;
};

template<class C, typename Func>
void exec(C *c, Func func)
{
    (c->*func)();
}

int main()
{
    Derived d;
    // Until here, everything compiles fine
    d.doStuff();
    // For some reason, I can't access the function pointer
    exec(&d,&Derived::doStuff);
}

g++ 编译上述代码失败:

test.cpp: In instantiation of ‘void exec(C*, Func) [with C = Derived; Func = void (Base::*)()]’: test.cpp:24:27: required from here
test.cpp:17:4: error: ‘Base’ is an inaccessible base of ‘Derived’ (c->*func)();

即使可以调用函数本身 (d.doStuff();),即使我声明该函数可以从外部访问,指针也不能使用。 在某种程度上,私有(private)继承也很重要,因为 Derived 类选择仅从作为接口(interface)实现 IRL 的基类中公开一组特定成员。

注意:这是关于语言的问题,而不是类设计。

最佳答案

问题在于&Derived::doStuff 实际上并不是一个指向Derived 类成员的指针。来自 [expr.unary.op]:

The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id. If the operand is a qualified-id naming a non-static or variant member m of some class C with type T, the result has type “pointer to member of class C of type T” and is a prvalue designating C::m.

doStuff 不是 Derived 的成员。它是 Base 的成员。因此它具有指向 Basevoid (Base::*)() 成员的类型指针。 using-declaration 在这里所做的只是帮助重载解析,来自 [namespace.udecl]:

For the purpose of overload resolution, the functions which are introduced by a using-declaration into a derived class will be treated as though they were members of the derived class.

这就是 d.doStuff() 起作用的原因。但是,通过函数指针,您试图在 Derived 对象上调用 Base 成员函数。这里没有重载解决方案,因为您直接使用函数指针,因此基类函数将无法访问。

您可能认为您可以将 &Derived::doStuff 转换为“正确”类型:

exec(&d, static_cast<void (Derived::*)()>(&Derived::doStuff));

但是根据 [conv.mem] 你也不能这样做,因为 Base 又是 Derived 的一个不可访问的基础:

A prvalue of type “pointer to member of B of type cv T”, where B is a class type, can be converted to a prvalue of type “pointer to member of D of type cv T”, where D is a derived class (Clause 10) of B. If B is an inaccessible (Clause 11), ambiguous (10.2), or virtual (10.1) base class of D, or a base class of a virtual base class of D, a program that necessitates this conversion is ill-formed.

关于c++ - 公共(public)访问声明不影响成员函数指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31518214/

相关文章:

C++ 是否使用放置新的未定义行为两次构造对象?

c++ - MSVC 用 double 支撑初始化似乎违反了标准?

c++ - 调用函数指针时出错

c++ - 使用 C++ 读取 HTML 文本

c++ - 使用 Visual Studios 2012 进行 C++ 编码时,如何自动完成在 IntelliSense 中选择的代码?

c++ - 与 boost::asio 一起使用的 std::string 的替代品

css - 用本地 css 替换全局 css

c++ - 接口(interface)和多重继承

inheritance - 动态获取对象的 is-a 关系

c++ - 在为嵌套类定义超出范围的友元时,我真的必须打破封装吗?