12
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++ の両方がエラーなしでコンパイルされます。

なんで?

4

3 に答える 3

8

次のコードは、標準では正しくありません。

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

それはGNU拡張です

ただし、clang にアクセスしようとするとエラーが発生するため、おそらく MSVC/GCC のバグです (メンバーにアクセスしようとすると、正しいエラーが表示されるためbBold、すべてこの拡張機能の実現に依存すると思います)。a

したがって、C-extensionアクセス指定子がないので、この匿名構造体のメンバーがセクションに注入されるように見えますpublic

于 2013-06-25T07:03:56.043 に答える
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 のバグでもあります。

于 2013-06-25T07:35:18.937 に答える
0

private/protected は、キーワードと同じクラスで定義されたフィールドのみを保護します。次のトリックを行う場合:

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

引き続きアクセスできますFoo::PublicBar::x

struct X { ... }は現在、C++ では のシノニムです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は非公開であり、内部結合の定義が公開に「漏れる」ことはありません。

于 2013-06-25T07:03:28.690 に答える