以下简单的代码片段,用VC2008编译,但g ++拒绝代码:
#include <iostream>
class myclass
{
protected:
void print() { std::cout << "myclass::print();"; }
};
struct access : private myclass
{
static void access_print(myclass& object)
{
// g++ and Comeau reject this line but not VC++
void (myclass::*function) () = &myclass::print;
(object.*function)();
}
};
int main()
{
myclass object;
access::access_print(object);
}
(/W4)
已在VC中启用,但不会发出任何警告。
g ++ 4.4.1给了我一个错误:
correct.cpp: In static member function ‘static void access::access_print(myclass&)’:
correct.cpp:6: error: ‘void myclass::print()’ is protected
如果g ++是正确的,我如何访问类的受保护成员?还有另一种方式吗?
@Suroot你的意思是我不应该传递myclass
类型的对象吗?实际上并不重要,g ++给出了相同的错误,但VC编译代码时没有任何警告。
#include <iostream>
class myclass
{
protected:
void print() { std::cout << "myclass::print();"; }
};
struct access : private myclass
{
static void access_print()
{
myclass object;
void (myclass::*function) () = &myclass::print;
(object.*function)();
}
};
int main()
{
access::access_print();
}
答案 0 :(得分:13)
这是对的。上面引用了标准的相关部分,但这是其价值的基本原理。
C ++中protected
的语义意味着“这个成员可以从这个类或任何派生类的方法访问,但只有当被访问的动态类型的对象保证与它相同时,才能访问,或者来自 *this
“的类型。
后一点可能不太明显,所以这是一个例子:
class Base {
protected:
int X;
};
class Derived : public Base {
void Foo(Base* b, Derived* d) {
this->X = 123; // okay - `this` is definitely either Derived
// or inherited from Derived
d->X = 456; // also okay, for the same reason
b->X = 789; // NOT OKAY; b could point to instance of some other class
// Derived2, which isn't inherited from Derived!
}
};
这是设计的 - 我们的想法是Derived2
可以对如何处理受保护的成员(不变量等等)有自己的看法,它应该严格地在它和它的基类之间(及其派生类,但仅当它决定不通过使其private
隐藏该字段时)。跨层次访问与此模型相反,因为它实际上意味着基类预先决定整个层次结构;对于深度层次结构之上非常抽象的类,这可能是不可取的。
现在回到你的具体问题 - 现在应该是相当明显的。获得成员函数指针后,可以使用匹配类型的任何接收器调用该指针指向的函数。对于基类的受保护方法,这意味着,如果你可以获得一个指向它的指针到基类(而不是你自己的类),你可以调用它,向它传递一个指向不同于你的类型的指针类(或从中派生),违反了上面概述的受保护访问规则。因此,您不得这样做。
答案 1 :(得分:6)
我相信g ++和comeau是正确的。受保护成员的说明符必须是“access”或派生类型,因此我相信代码:
void (myclass::*function) () = &access::print;
会编译。
我认为这是因为11.5.1:
...如果访问[ed。受保护的 成员]是形成一个指针 member,嵌套名称说明符 应命名派生类(或任何 从该类派生的类)。
答案 2 :(得分:2)
由于对象作为参数传递,因此无法直接访问私有/受保护函数。
编辑: 将myclass更改为object