派生 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
形成指向受保护成员的指针是不正确的。
#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 denoteC
or a class derived fromC
. All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall beC
or a class derived fromC
. [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
形成指向受保护成员的指针是不正确的。