我想要的是某些班级成员有时候private
而其他班次public
。这些成员应该可以被某些模块访问,而其他模块则无法访问。
对此课程进行成像:
class Foo {
public:
...
private:
...
protected:
...
internal:
int x;
};
在模块X中,internal
定义为:
#define internal public
并在模块Y中定义为:
#define internal private
所以真正的问题是标准是否可以接受这个技巧,或者它是否会以任何方式改变类(或其成员)的签名。
我知道friend
和PIMPL
适用于此类工作,但friend
会变得非常混乱和PIMPL
的表现(间接和事实你无法内联)对于我正在处理的代码库是不可接受的。
答案 0 :(得分:4)
这是ODR违规,因此会调用未定义的行为。 (参见basic.def.odr] /6.1“D的每个定义应由相同的令牌序列组成”)。
但是,一个常见的实现是public,private,protected对类布局没有影响,因此它可以工作。
你在薄冰上滑冰;没有什么可以阻止编译器将所有公共成员放在第一位,然后是受保护的成员,然后是私有成员。更重要的是,一般来说,声明的顺序必须是内存中的顺序,所以struct T {char a; int b; char c};
必须包含a
,然后是b
,然后是c
。这是为了确保C兼容性。但是,对具有不同访问权限的元素的排序没有要求(参见[class.mem] /9.2 p13:“具有相同访问控制(第11章)的(非联合)类的非静态数据成员被分配,以便后来的成员在一个类对象中有更高的地址。具有不同访问控制的非静态数据成员的分配顺序是未指定的(第11条)“。所以给定
struct T {char a; int b; private: char c};
编译器可以对成员进行重新排序,并将c
放在a
和b
之间。
对EJP和其他认为这些声明不是定义的人的最后说明:我已经给出了T
以上的两个定义; 声明看起来像struct T;
。
编辑:感谢Fanael来自标准的引用。
答案 1 :(得分:0)
C ++最初似乎认为私有成员可以放在公共成员旁边的某个地方,也许这样他们可能是硬件中的受保护区域,因此可以想象公共和私人部分可以相对于每个部分移动其他。
可以在不使用Herb Stutter GOTW 76的技巧重新定义公共/私人的情况下测试您的代码,并在此处使用此数据完成功能完整的系统litb safer private member access
给出如下课程......
struct A {
A(int a):a(a) { }
private:
int a;
};
需要强盗类......
template<typename Tag, typename Tag::type M>
struct Robber {
friend typename Tag::type get(Tag) {
return M;
}
};
允许多次抢断的实用程序类......
template<typename Tag, typename Member>
struct TagBase {
typedef Member type;
friend type get(Tag);
};
宣布盗窃意图成为
struct A_f : TagBase<A_f, int A::*> { };
template struct Robber<A_f, &A::a>;
然后窃取数据......
int main() {
A a(42);
std::cout << "proof: " << a.*get(A_f()) << std::endl;
}