独習C++ 読書ログ 2章

P71

  • 構造体のメンバーにアクセスする方法
    1. ドット演算子 (. : dot operator)
      • アクセスする先の構造体が構造体変数
      • structure-variable.member-name
    2. アロー演算子 (-> : arrow operator)
      • アクセスする先の構造体が構造体変数へのポインターなのか
      • pointer-to-structure-variable.member-name

アロー演算子の場合は、ポインターなので間接参照演算子を使って、a->b なのであれば (*a).b と書き換えることもできる。

構造体って C# だと値型だけど、C++ だとそういう感じではないのかな。関数は生やせないみたいなのでそこも違うか。

P72

構造体の初期化。{} を使って配列のように初期化できる。

struct product
{
    int id;
    int price;
}

product a = {
    0, // id
    100  // price
};

P74

共用体。構造体に似ているが、すべてのメンバー変数が同じアドレスを参照している。

使い道はわからん。

P78

列挙体。

  • enum Class enum-name で始める
  • C# のような enum enum-name は C スタイルでスコープ解決演算子を省略できたりするので推奨しない

P81

クラス概要。

  • 構造体との違いは、データに加えてその処理もまとめて扱うこと。
  • 構造体と同様に変数を作った上で扱うが、そのことを 実体化やインスタンス化(instantiation) と呼ぶ
    • 構文はほとんど構造体と同じ struct の代わりに class を使う

P86

参照。

おいおい、なんでアドレス演算子と同じ & を使うんだよ。

type-name& reference-name = variable-name

参照とポインターの違い

int value = 42;

int* pointer = &value; // アドレス演算子でアドレスを取得し、ポインター変数に格納
int& reference = value; // 参照を格納。内部としてはアドレスを共有しているのだと思う。

// pointer のアドレス
pointer

// reference のアドレス。アドレスを共有しているが値なのでアドレス演算子が必要。
&reference

// pointer の値。ポインター変数なので間接参照演算子で値を取り出す。
*pointer

// reference の値。値なのでそのまま。
reference

参照は後から付け替えられない。

int value = 42;
int ohter = 0;

int& reference = value;
reference = other;

// other の値が reference の値に入っただけで、reference のアドレスは value のままになる。
// &other != &reference

const参照

参照はそもそもアドレスを変更できないので、参照する値が const になっている。
注意点としては、const な値や const な参照をさらに参照で受ける場合に、受ける側も const をつけなければいけない。

const int constant = 42; // const な値
const int& ref_constant = constant; // const な参照

int& ref1 = constant; // NG
const int& ref1 = constant; // OK

int& ref2 = refconstant; // NG
const int& ref2 = refconstant; // OK

P94

式の型を推論する

decltype(expression) で使える。typeof みたいな単に型を調べるだけではなくて、それで宣言にも使える。
TypeScript の ReturnType みたいな感じなんやろか。。この時点では利用例が無いので不明。

P95

配列の型推論

なんか突然 auto array[] {0, 1, 2} みたいな、これまでに無い配列の初期化の方法がでてきたりでよく分からない。

とりあえず、「型推論を使うことでは配列を宣言できない」ということらしいので忘れる。

P97

型の別名定義

using new-type-name = old-type-name C# と同じに見える。
関数内でも使えるよう。

ネストした型名

  • class の内部でさらに別名定義ができる
  • 関数の実装の戻り値など、クラスのスコープ外ではフルネームで書くが、関数の実装の内部であれば、別名を直接呼び出せる。
class data
{
public:
    using interger = int;

    // ここは class の内部なので integer が使える
    integer get_value();
    void set_value(integer new_value);

private:
    integer value;
};

// class の外側なので data::integer とフルネームで
data::integer data::get_value()
{
    return value;
}

// 引数は class の内側という扱いらしい
void data::set_value(integer new_value)
{
    // ここも内側
    integer tmp = new_value;
    value = tmp;
}

C言語との互換性

typedef old-type-name new-type-name

using と逆の順番。

P101

コンソールからの入力

  • std::cin 入力受付。宣言済の変数に値を格納。
    • ただし、指定した変数の型通りにしか受け取れず、std::string で受けた場合には空白が無視されたり、空白で切られたりする
  • std::istream& getline(std::istream& input, std::string& str) で 1行をすべて受け取れる
    • 使い方としては std::getline(std::cin, s) のような形。std::cinistream らしい。

P109

デフォルト引数

C# と同じような感じ。可変長とか名前付き引数もあるんだろうか。

P111

ラムダ式

[](parameters...) -> return-type
{
    lambda-body
}

ラムダ式は必ず auto で受ける必要があるらしい。コンパイラーが作ったユニークな型が割り当てられるため。decltype でもそれを再利用はできない。

戻り値の型の省略

型推論で省略可能。

[](parameters...)
{
    lambda-body
}

まさかのアローが消された。

変数のコピーキャプチャ

  • ラムダ式の先頭の [] がキャプチャ対象の指定になっている。
  • [variable, variable...][=, variable, variable...] のいずれか。
  • =ラムダ式内で使っている変数をコンパイラーが自動でキャプチャする。
    • [=] でいいらしいが、他に変数を指定する用途はなんだろうか?

変更可能なコピーキャプチャ

  • コピーとしてキャプチャしいた変数は暗黙的に const となる
  • キャプチャした変数事態を変更する場合には、mutable 指定する
    • ただし、キャプチャした変数すべてが対象となる
[variable, variable...](parameters...) mutable -> return-type
{
    lambda-body
}
  • 当然ながらコピーなので、変更したとしてもコピー元の変数に影響は無い。

参照を取得するキャプチャ

  • 当然コピー以外に参照をキャプチャするケースもある
  • この場合は mutable 不要で変更可能
    • ただし、キャプチャした変数が元々 const であれば変更不可
[&variable, &variable...](parameters...) mutable -> return-type
{
    lambda-body
}

[&, &variable, &variable...](parameters...) mutable -> return-type
{
    lambda-body
}

先頭に & を付けるのは、デフォルトのキャプチャ = の代わりに、デフォルトのキャプチャをすべて参照で行うことを宣言する。