LoginSignup
3
0

More than 3 years have passed since last update.

勉強記録 11日目 〜constなメンバ関数〜 - Effective C++ 第3版 -

Last updated at Posted at 2019-12-05

 はじめに

Effective C++ 第3版の3項10ページから勉強していきます。
今回は、「constなメンバ関数」についです。

Effective C++ 第3版 - 3項 可能ならいつでもconstを使おう -

constなメンバ関数

メンバ関数にconst修飾子を付ける理由

メンバ関数にconst修飾子を付けるのは、
「その関数がconstなオブジェクトに対して使われる」or「メンバ関数を呼び出し、実行した時に、メンバ変数を変更する必要がない」ときに使われる。

そのような関数が重要である理由は2つあります。
1つ目は、「クラスのインタフェースを理解しやすくする」という理由です。
どのメンバ関数がオブジェクトを変更し、どのメンバ関数が変更しないか、という区別に容易につけられることは重要でしょう。
2つ目は、「constなオブジェクトに対して使える」という理由です。

次の、TextBlockというクラスについて考えてみます。

class TextBlock {
 public:
 explicit TextBlock(std::string text) : text_(text){};
 const char& operator[](std::size_t position) const { return text_[position]; };
 char& operator[](std::size_t position) { return text_[position]; };
 // char& operator[](std::size_t position) const { return text_[position]; }; // コンパイルエラー
 void testFunc() const { std::cout << "text : " << text_ << std::endl; };
 // void testFunc() { std::cout << __func__ << " : 2" << std::endl; }

 private:
 std::string text_;
};

メンバ関数の右側にconstをつけると、そのメンバ関数内ではメンバ変数の変更ができなくなります。
このメンバ関数をconstメンバ関数と呼んだりもします。
下の2つが、TextBlockのconstメンバ関数です。

class TextBlock{
 public:
 void testFunc() const { std::cout << "text : " << text_ << std::endl; };
 const char& operator[](std::size_t position) const { return text_[position]; };
 ...
};

また、オーバーロードで、constの有る無しだけが異なる2つのバージョンの[]演算子を書くと、
constでないTexttBlockに対しても、constなTextBlockに対しても、[]演算子を使うことができる。
TextBlockとconstなTextBlockを生成し、[]演算子を使用すると、下記のようになる。

TextBlock tb("Hello");
std::cout << tb[0] << std::endl; // constでないTextBlock::operator[]を呼び出す
tb[0] = 'a'; // 代入可能

const TextBlock ctb("World");
std::cout << ctb[0] << std::endl; // constありのTextBlock::operator[]を呼び出す
// ctb[0] = 'a'; // コンパイルエラー // 代入不可

const付きのTextBlockはconst付きのoperator[ ]を呼び出している。

constなしのTextBlockの[ ]演算子の返り値は参照のため、読み込み・書き込みが可能である。
constありのTextBlockの[ ]演算子の返り値はconstが付いているため、読み込みのみ可能である。

また、関数の引数のポインタ渡しや参照渡しに、constなオブジェクトがよく使われる。

 // const char& operator[](std::size_t position) const が呼ばれる
void print(const TextBlock& ctb) { std::cout << ctb[0] << std::endl; }

print(ctb);
print(tb);

上のような場合は、print関数内でconst付きのoperator[ ]が呼ばれる。

class TextBlock {
 public:
 ...
 char& operator[](std::size_t position) const { return text_[position]; }; // コンパイルエラー
 ...
};

また、上のコードでエラーがでる理由は、
「関数内で値は変更していないが、参照返しのため、戻り値で代入できる。」
のためである。

以下に、勉強で使用したコードを示します。

サンプルコード

3_const_itr.cpp
#include <iostream>
#include <vector>

class TextBlock {
 public:
 explicit TextBlock(std::string text) : text_(text){};
 const char& operator[](std::size_t position) const { return text_[position]; };
 char& operator[](std::size_t position) { return text_[position]; };
 // char& operator[](std::size_t position) const { return text_[position]; }; // エラーがでる理由
 void testFunc() const { std::cout << "text : " << text_ << std::endl; };
 // void testFunc() { std::cout << __func__ << " : 2" << std::endl; }

 private:
 std::string text_;
};

void print(const TextBlock& ctb) { std::cout << ctb[0] << std::endl; } // const char& operator[](std::size_t position) const が呼ばれる

int main(int argc, char* argv[]) {
 std::cout << "3_const_mem.cpp" << std::endl;
 TextBlock tb("Hello");
 std::cout << tb[0] << std::endl; // constでないTextBlock::operator[]を呼び出す
 tb[0] = 'a';
 std::cout << tb[0] << std::endl;

 const TextBlock ctb("World");
 std::cout << ctb[0] << std::endl; // constなTextBlock::operator[]を呼び出す
 tb.testFunc();
 ctb.testFunc();
 print(ctb);
 print(tb);
}

実行結果

3_const_mem.png

参考文献

https://www.amazon.co.jp/gp/product/4621066099/ref=dbs_a_def_rwt_hsch_vapi_taft_p1_i0

3
0
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
0