3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

読み取り専用メンバー変数

Last updated at Posted at 2016-04-02

constメンバー変数とvectorの問題

@chikashimiyamaさんの記事に対してコメントした妥協案より良さそうな実装を思いついたので、メモしておく。
コメントした妥協案の最大の不満点は、

  • コンストラクター、代入演算子の実装が面倒臭い

ことである。これは、結局コピー/ムーブできないconstメンバー変数を抱えているからだ。
そこで、メンバー変数をクラスの外に出し、書き込みできないように関数経由で読み取るようにしてみる。

#include <vector>
#include <iostream>

template <class T>
class AutoROData
{
    T m_data;

  public:
    explicit AutoROData(const T &data)
        : m_data{data}
    {}

    const T &operator()() const {
        return m_data;
    }
};

class WithConst
{
  public:
    WithConst(const int value1, const int value2)
        : value1{value1}
        , value2{value2}
    {}

    int getConstValue1() const {
        return value1();
    }
    void setConstValue1(const int value1) {
//      this->value1 = value1; // 間違って書き換えようとしても、コンパイルエラーになる
    }

    int getValue2() const {
        return value2;
    }
    void setValue2(const int value2) {
        this->value2 = value2;
    }

  protected:
    AutoROData<int> value1;
    int value2;
};

int main()
{
    std::vector<WithConst> vec{
        {20,21},
        {30,31},
        {40,41}
    };
    vec.erase(vec.begin()+1);
    for ( const auto &v : vec ) {
        std::cout << v.getConstValue1() << "," << v.getValue2() << '\n';
    }
}

データ用クラスを一々実装するのも面倒臭い1のでテンプレートにしている。

AutoROData<T>型のオブジェクトは、コピー/ムーブできるようにするために代入演算子を削除していないが、元の型(T型)ではなくAutoROData<T>型のオブジェクトを代入する必要があるので、間違って代入してしまうことはないだろう。
これで、WithConstクラス自体はコピー/ムーブできるが、メンバー変数value1は読み取り専用(に見えるよう)になった。

おまけ

メンバー変数value1から元のint型の値を読み取るためには関数形式value1()で呼び出す必要があるので、多少違和感がある。
そこで、C++標準委員会に提出された「C++ Properties -- a Library Solution」を参考にプロパティ化すると、自然に見えるようになる。

#include <vector>
#include <iostream>

template <class T>
class AutoROProperty
{
    T m_data;

  public:
    explicit AutoROProperty(const T &data)
        : m_data{data}
    {}

    operator const T &() const {
        return m_data;
    }
};

class WithConst
{
  public:
    WithConst(const int value1, const int value2)
        : value1{value1}
        , value2{value2}
    {}

    int getConstValue1() const {
//      return value1();
        return value1; // 元のint型の値を読み取る場合と全く同じように書ける
    }
    void setConstValue1(const int value1) {
//      this->value1 = value1; // 間違って書き換えようとしても、コンパイルエラーになる
    }

    int getValue2() const {
        return value2;
    }
    void setValue2(const int value2) {
        this->value2 = value2;
    }

  protected:
//  AutoROData<int> value1;
    AutoROProperty<int> value1;
    int value2;
};

int main()
{
    std::vector<WithConst> vec{
        {20,21},
        {30,31},
        {40,41}
    };
    vec.erase(vec.begin()+1);
    for ( const auto &v : vec ) {
        std::cout << v.getConstValue1() << "," << v.getValue2() << '\n';
    }
}
  1. プログラマーは面倒臭がり屋である(^^;

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?