Допустим, у меня есть следующие два определения класса (только спецификатор доступа для 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 ++ путем определения конкретного макроса в «пакете».
Это определенно неопределенное поведение — нарушать правило одного определения, которое требует, чтобы все определения одного и того же типа класса были идентичными.
Обратите внимание, что макет памяти класса указывается только в пределах каждого уровня доступа, Таким образом, изменение уровней доступа может очень реалистично привести к разной структуре памяти класса.
Казалось бы, это не будет хорошей идеей
изменение прав доступа к некоторым функциям или элементам данных, для
пример из частного в публичный. С некоторыми компиляторами эта информация
может быть частью подписи. Если вам нужно сделать частную функцию
защищенный или даже публичный, вы должны добавить новую функцию, которая вызывает
частный.
Тем не менее, я не думаю, что это должно привести к неопределенному поведению, а скорее к ошибке ссылки или ошибке загрузки символа.
ОБНОВИТЬ:
Тестирование на GCC (4.6.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