公共访问声明不影响成员函数指针?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (43)

我有一个关于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:实例化'void exec(C *,Func)[with C = Derived; Func = void(Base :: *)()]':test.cpp:24:27:此处需要 test.cpp:17:4:error:'Base'是'Derived'的一个不可访问的基址(c-> * FUNC)();

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

注意:这是一个关于语言的问题,而不是课程设计。

提问于
用户回答回答于

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

一元运算&符的结果是一个指向其操作数的指针。操作数应该是一个左值或一个合格的ID。如果操作数是一个合格-ID命名非静态或变体构件m某些类的C类型T,结果类型“指针类的成员C类型的T”,并且是一个指定prvalue C::m

doStuff不是。的成员Derived。它是一个成员Base。因此它有指向成员的类型指针Base,或者void (Base::*)()。这里使用声明所做的只是对重载解析的帮助,来自[namespace.udecl]:

为了重载解析的目的,通过使用声明引入到派生类中的函数将被视为它们是派生类的成员。

这就是为什么d.doStuff()工作。但是,通过函数指针,您正尝试BaseDerived对象上调用成员函数。这里没有重载解析,因为你直接使用函数指针,所以基类函数将无法访问。

你可能会认为你可以&Derived::doStuff转换成“正确”的类型:

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

但是根据[conv.mem],你不能这样做,因为再次Base是一个无法访问的基础Derived

一个类型为“ B类型为cv的 成员的指针T” 类型的值,其中B是一个类类型,可以被转换为类型为“指向D类型为cv的 成员的指针”的prvalue T,其中D是派生类(第10章)B。如果B不可访问的(第11章),需要进行此转换的程序的模糊(10.2)或虚拟(10.1)基类D或虚拟基类的基类D不合格。

用户回答回答于

我想原因是成员函数不是派生类的一部分,而是基类的一部分。这可以通过检查成员函数指针的类型并将其与指向基本成员函数的指针进行比较以某种方式凭经验显示:

cout << typeid(&Derived::doStuff).name() << endl
  << typeid(& Base::doStuff).name() << endl;

这里。

所属标签

可能回答问题的人

  • 天使的炫翼

    17 粉丝531 提问9 回答
  • 优惠活动秘书

    0 粉丝2 提问8 回答
  • 最爱开车啦

    8 粉丝503 提问6 回答
  • 富有想象力的人

    3 粉丝0 提问5 回答

扫码关注云+社区

领取腾讯云代金券