派生 class 中受保护的成员函数地址不可访问

Protected member function address in derived class is not accessible

#include <iostream>

class A {
protected:
    void foo()
    {}
};

class B : public A {
public:
    void bar()
    {
       std::cout << (&A::foo) << std::endl;
    }
};

int main()
{
    B b;
    b.bar();
}

这里我试图获取基class的受保护成员函数的地址。我收到此错误。

main.cpp: In member function ‘void B::bar()’:
main.cpp:5: error: ‘void A::foo()’ is protected
main.cpp:13: error: within this context
make: *** [all] Error 1

将 foo 更改为 public 有效。打印 &B::foo 也有效。您能解释一下为什么我们无法获取基class的受保护成员函数的地址吗?

看来我找到了答案。如果我们可以获得成员函数的指针,我们就可以为类型为 A(不是 this)的其他对象调用它,这是不允许的。

对于 this 以外的对象,不允许在派生 类 中调用受保护的成员函数。获取指针会很暴力。

我们可以这样做:

#include <iostream>

class A {
protected:
    void foo()
    {}
};

class B : public A {
public:
    void bar()
    {
        void (A::*fptr)() = &A::foo;

        A obj;
        (obj.*fptr)();

        // obj.foo(); //this is not compiled too.    
    }
};

int main()
{
    B b;
    b.bar();
}

我很好奇并尝试了以下示例:

#include <iostream>
using namespace std;

class A {
public:
    void foo()
    {
    }
};

class B : public A {
public:
    void bar()
    {
       printf("%p\n", (&A::foo));
       printf("%p\n", (&B::foo));
    }
};

int main()
{
    B b;
    b.bar();
}

实际上,我看到 &A::foo == &B::foo,因此对于基 class 的受保护成员,您可以使用派生 class 成员来获取地址。我想在虚函数的情况下这将不起作用

B 可以访问 A 的受保护成员,只要访问是通过类型 B 的对象执行的。在您的示例中,您试图通过 A 访问 foo,在这种情况下,B 是否源自 A 是无关紧要的。

来自 N3337,§11.4/1 [class.protected]

An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class (11.2) As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C. If the access is to form a pointer to member (5.3.1), the nested-name-specifier shall denote C or a class derived from C. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C. [Example:

 class B {
 protected:
   int i;
   static int j;
 };
 class D1 : public B {
 };
 class D2 : public B {
   friend void fr(B*,D1*,D2*);
   void mem(B*,D1*);
 };
 // ...
 void D2::mem(B* pb, D1* p1) {
   // ...
   int B::* pmi_B = &B::i; // ill-formed
   int B::* pmi_B2 = &D2::i; // OK
   // ...
 }
 // ...

—end example]

您的示例与 D2::mem 中的代码非常相似,它表明试图通过 B 而不是 D2 形成指向受保护成员的指针是不正确的。