朋友调用虚拟私有方法-应该发生什么

friend calls virtual private method - what should happen

本文关键字:什么 调用 虚拟 有方法 朋友      更新时间:2023-10-16

我有一种情况,我想让一个朋友类调用一个私有方法,然后我想让这个方法虚拟化,这样派生类的方法就会被调用——然后我当然意识到友谊不是继承的。因此,我们有一种情况,虚拟方法意味着应该调用派生类的方法,但这个方法是私有的,因此不能调用。哪个优先?

我在MSVC++2008上测试了如下

#include<iostream>
class Loner;
class Base
{
    friend Loner;
private:
    virtual void test(){std::cout << "Base" << std::endl;}
};
class Derived : public Base
{
private:
    virtual void test(){std::cout << "Derived" << std::endl;}
};
class Loner
{
public:
    void test(Base *base){base->test();}
};
int main()
{
    Loner loner;
    Derived derived;
    loner.test(&derived);
}

输出为:

Derived

因此,虚拟功能似乎"获胜",并允许私人成员访问非朋友——几乎是朋友继承!

我的问题是,有人知道这是否是正确的行为吗?当我终于抽出时间升级我的编译器版本时,或者如果我尝试GCC,这种行为会改变吗?

干杯

Phil

§11.5/1-2([class.access.virt]):

  1. 虚拟函数的访问规则(第11条)由其声明决定,不受后来覆盖它的函数的规则的影响。

  2. 访问在调用点使用表达式的类型进行检查,该表达式用于表示调用成员函数的对象。。。

所以你很适合升级。(实际标准中有一个例子,但我把它排除在报价之外。)

实际上,这里发生的是Base虚拟函数对其覆盖进行发送。因此,即使您不能静态调用Derived覆盖(Derived::member),如果您有权访问Base::member,您仍然可以让Base::member为您调用它。

调用是通过"static"类型为Base*的对象指针进行的,这是执行访问检查的类型。这些访问检查发生在编译时。由于LonerBase的朋友,因此编译器可以允许调用base->test()

然而,base指针指向的对象的动态类型是Derived。在运行时,没有额外的访问检查——调用是对动态类型进行的,动态类型是通过正常的虚拟调用机制进行调度的。