Могут ли макрос-зависимые спецификаторы доступа в определении класса привести к неопределенному поведению?

Допустим, у меня есть следующие два определения класса (только спецификатор доступа для 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 ответе (так как это мой основной целевой компилятор).

Это становится интересным, если мы хотим «симулировать» такие вещи, как package private из мира Java в C ++ путем определения конкретного макроса в «пакете».

2

Решение

Это определенно неопределенное поведение — нарушать правило одного определения, которое требует, чтобы все определения одного и того же типа класса были идентичными.

Обратите внимание, что макет памяти класса указывается только в пределах каждого уровня доступа, Таким образом, изменение уровней доступа может очень реалистично привести к разной структуре памяти класса.

4

Другие решения

Казалось бы, это не будет хорошей идеей

изменение прав доступа к некоторым функциям или элементам данных, для
пример из частного в публичный. С некоторыми компиляторами эта информация
может быть частью подписи. Если вам нужно сделать частную функцию
защищенный или даже публичный, вы должны добавить новую функцию, которая вызывает
частный.

Политики / Проблемы двоичной совместимости с C ++

Тем не менее, я не думаю, что это должно привести к неопределенному поведению, а скорее к ошибке ссылки или ошибке загрузки символа.

ОБНОВИТЬ:

Тестирование на GCC (4.6.1), изменение прав доступа работало без проблем.

1

Не прямой ответ — просто идея

С умным использованием 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
0
По вопросам рекламы [email protected]