类定义中的宏依赖访问说明符是否会导致未定义的行为?

时间:2012-09-27 20:33:47

标签: c++ compiler-construction undefined-behavior

假设我有以下两个类定义(只有bar()的访问说明符不同,其他一切都相同):

class MyClass {
public:
    void foo();
    void bar();   // bar() is public

private:
    int member;
};

class MyClass {
public:
    void foo();

private:
    void bar();   // bar() is private
    int member;
};

编译器是否认为类在编译器生成的代码方面“不同”? (或者换句话说:除了访问权限检查之外,编译器是否会对它进行不同的处理?)

这是同样的问题:以下代码是否会导致未定义行为等问题? (如果它是以不同的单位编制的,有或没有定义X,并在之后链接在一起。)

class MyClass {
public:
    void foo();

#ifdef X
private:
#endif
    void bar();

private:
    int member;
};

我对独立于编译器的答案以及特定于GCC的答案感兴趣(因为这是我的主要目标编译器)。

如果我们想通过在“包”中定义特定的宏来从C ++中的Java世界“模拟”package private之类的东西,这就变得很有趣。

3 个答案:

答案 0 :(得分:4)

违反单定义规则肯定是未定义的行为,这要求同一类类型的所有定义都相同。

请注意,类的内存布局仅在每个访问级别中指定,因此更改访问级别可以非常逼真地导致类的不同内存布局。

答案 1 :(得分:1)

这似乎不是一个好主意:

  

更改某些功能或数据成员的访问权限   从私人到公共的例子。有些编译器,这个信息   可能是签名的一部分。如果你需要私人功能   受保护甚至是公共的,你必须添加一个调用的新函数   私人的。

     

- Policies/Binary Compatibility Issues With C++

但是,我不认为这会导致未定义的行为,而是应该导致链接错误或符号加载错误。

<强>更新

在GCC(4.6.1)上进行测试,更改访问权限没有问题。

答案 2 :(得分:0)

不是直接回答 - 只是一个想法:

通过智能使用friend关键字,您可以获得与libprivate黑客相同的效果。您可以限制只访问您的部分隐私。您只需要使用friend两次:

class Example {
private:
   typedef int A;
   void fooA() {}
   static void barA() {}

   typedef int B;
   void fooB() {}
   static void barB() {}
   friend class LibAccessToExample;
}; 

#ifdef libprivate
class LibAccessToExample {
private:
   typedef Example::B B;
   static void  fooB(Example& e) { e.fooB(); }
   static void  barB() { Example::barB(); }
   // and all the classes needed this access at some state
   friend class Example1;
   friend class Example2;
   friend class Example3;
   friend class Example4; 
};
#endif

通过智能地使用宏,您可以更轻松地编写代码:

#define LIBCLASSES friend class Example1; friend class Example2; ...
#define FRIENDNAME(clazz) LibAccessTo##clazz
#define FWDDEF(clazz, type) typedef clazz::type type
...

#ifdef libprivate
class FRIENDNAME(Example) {
private:
   FWDDEF(Example, B);
   FWDSTATICFUNC(Example, void, fooB);
   FWDFUNC(Example, void, fooB);
   LIBCLASSES;
};
#endif