Почему защита не защищает участника в этом классе?

class Base {
    protected:
        union {
            struct {
                bool bBold : 1;
                bool bFakeBold : 1;
            };
            int a;
        };
    public:
        bool isBold() {
            return bBold;
        }
};

Класс тестирования:

#include <assert.h>
#include <stdio.h>

int main()
{
    Base d;
    d.bBold = false;
    assert(d.isBold() == false);
    d.bBold = true;
    assert(d.isBold() == true);
    printf("good");
    return 0;
}

Оба msvc11 и g++ компилируются без ошибок.

Почему?

Ответ 1

Следующий код неверен по стандарту.

        struct {
            bool bBold : 1;
            bool bFakeBold : 1;
        };

GNU-расширение

Однако, clang дает ошибку, когда вы пытаетесь получить доступ к bBold, поэтому, вероятно, это ошибка MSVC/GCC (все зависит от реализации этого расширения, я думаю, поскольку, если вы попытаетесь получить доступ к a член - вы получите правильную ошибку).

Итак, поскольку он C-extension, где у нас нет спецификаторов доступа, похоже, что члены этой анонимной структуры будут вставляться в раздел public.

Ответ 2

Как уже упоминалось, неназванные структуры являются нестандартным расширением. Поскольку это нестандартное расширение, для разных компиляторов допустимо реализовать это по-разному. Однако для анонимных профсоюзов существует тот же вопрос. Модифицированный пример:

class C {
    union {
        union {
            int i;
        };
    };
};
int main() {
    C c;
    c.i = 0;
    return c.i;
}

Это должно привести к ошибке/предупреждению/другой диагностике компиляции, но GCC с радостью принимает ее. Протестировано с помощью 4.5.3 и Ideone 4.7.2. Я подозреваю, что это ошибка в GCC, и если MSVC также принимает это, также ошибка в MSVC.

Ответ 3

Частные/защищенные защищают только поля, определенные в том же классе, что и ключевое слово. Если бы вы сделали следующий трюк:

class Foo {
    private:
    class Bar {
        public:
        int x;
    }
    public:
    typedef Bar PublicBar;
}

Вы можете получить доступ к Foo::PublicBar::x

struct X { ... } теперь в С++ синоним class X { public: ... }. Области союза также являются общественными.

В вашем случае вы можете скрыть его следующим образом:

class Base {
protected:
    union X {
        struct {
            bool bBold : 1;
            bool bFakeBold : 1;
        };
        int a;
    };
    X x;
public:
    bool isBold() {
        return x.bBold;
    }
};

Теперь x является закрытым, и определение внутреннего объединения не "течет" публично.