2019年12月6日金曜日

[C++] 本当に private なところ

※ この記事は「C++ Advent Calendar 2019」6日目の投稿です。


private メンバー変数の R/W テスト
まずはこちらをご覧ください。
#include "iutest.hpp"
//origin>> #include "../../include/iutest.hpp"
#include <iostream>

int main(int argc, char** argv)
{
    IUTEST_INIT(&argc, argv);
    return IUTEST_RUN_ALL_TESTS();
}

class Test
{
private:
    int A:12;
    int B:4;
    int C:4;
    int D:12;
    int E;
public:
    Test()
        : A(0x777)
        , B(0x3)
        , C(0x4)
        , D(0x400)
        , E(1)
    {}
};

IUTEST_MAKE_PEEP(int Test::*, Test, E);

IUTEST(PeepTest, MemberVariable)
{
    ::Test test;
    IUTEST_EXPECT_EQ(1, IUTEST_PEEP_GET(test, ::Test, E));
    IUTEST_PEEP_GET(test, ::Test, E) = 4;
    IUTEST_EXPECT_EQ(4, IUTEST_PEEP_GET(test, ::Test, E));
}
https://wandbox.org/permlink/GqDQ4zeCrzv1HABq

private メンバーである Test::E への書き込み・読み込みができていることがわかると思います。

private メンバー変数(ビットフィールド)の R/W テスト
続いて、上でアクセスしている private 変数を E から A に変えてみます。

IUTEST_MAKE_PEEP(int Test::*, Test, A);

IUTEST(PeepTest, MemberVariable)
{
    ::Test test;
    IUTEST_EXPECT_EQ(1, IUTEST_PEEP_GET(test, ::Test, A));
    IUTEST_PEEP_GET(test, ::Test, A) = 4;
    IUTEST_EXPECT_EQ(4, IUTEST_PEEP_GET(test, ::Test, A));
}
https://wandbox.org/permlink/NRPvHweGaDp6HAdy

今度はコンパイルエラーです。

解説
プライベートにアクセスした方法
上のコードで利用したテスティングフレームワークは iutest です。
private メンバーへのアクセスはこのフレームワークの PEEP 機能を利用しています。
PEEP は template explicit instantiation で private にアクセス可能なことを利用して、private メンバーのアドレスを取得して実現しております。
詳しくは昔書いたこちらの記事を参考にしてください。(「ブログズミ: [C++] Private な関数のテスト」)

ビットフィールドにアクセスできなかった理由
error: address of bit-field requested
上記 PEEP の方法ではアドレスを取得できる必要があるため、
アドレスが取れないビットフィールドではアクセスできないわけです。
(言語法律家によるアクセスが可能な場合はビットフィールドでもアクセスできますが・・ : https://wandbox.org/permlink/zYC1hAYuqqixaEUn

まとめ
C++ にプライベートはあった

0 件のコメント:

コメントを投稿