ロベールのC++入門講座

やっぱ文法もやったほうがいいなと思って、C++の入門書買ってきた。

ロベールのC++入門講座

ロベールのC++入門講座

出版社がマイコミなので、OS自作入門と同じようなノリ(喋り口調な解説)で楽しく読めるのがいい感じ。

口調は軽いけど内容は案外しっかりしてて、Cとの違いもキッチリ解説してあるので、Cからの乗換えでC++をサックリ覚えたい人にはオススメ。(乗り換えたつもりはあんまり無いけど)


1000ページくらいあるけどあんまりムズくないので、数時間で読了できそうだ(嘘かも)。ガガッっとよむべ。

以下メモ

1章 - まずは使い方

  • 統合開発環境とか面倒過ぎて使えないんだけど、便利なのアレ?
  • ボタンがいっぱいあってよくわかんなくなっちゃうんだよね。
  • g++,make,Vim,後gdbがあればいいと思う。

2章 - C++の基本

  • プログラムはじめた時は=の意味の違いに戸惑った気がする。

3章 - ほんの少し深く

  • 'A'はC++でchar, Cではint
    • sizeofするとわかる。
    • eofについて調べる必要アリだな。
  • randの使い方は参考になった。
  • cmath(math.h)に関すること
    • 最近スゲーよく使うので。
    • fabsを使うと安全らしい。
    • log10あり。底の変換公式を使う頻度がちょっと減る。
    • modf,fmodが便利そうだ。
  • coutの引数の評価順序は右から行われるらしい。(コレは書いてないけど)
#include <iostream>
using namespace std;

int test(int i)
{
    cout << i * i << " ";
    return i;
}

int main()
{

    cout << test(1) << " " << test(2) << " " << test(3) << endl;

    return 0;
}
    • 実行結果は9 4 1 1 2 3
    • おっと師匠から突込みが。「coutの中」と書きたかったのですハイ。

おぉっと

昨日の補足(C++)ありがとう師匠!!

#include <iostream>

int main()
{
    std::endl(operator<<(operator<<(operator<<(std::cout, "hello, "), "world"), " (" __DATE__ ")"));

    return 0;
}

うは、スゲーわかりやすいな。引数は右から左に評価されるので、testの評価順序も納得がいく。

(引数の評価順序は実装依存らしい)

続き

  • 浮動小数
    • 二進数でダンプできないので違いがよくわからず。bitsetも使えなかったし。
    • 浮動小数→2進変換ってどうやるんだろう。
    • とりあえずstdioで試す。
#include <cstdio>

int main()
{
    for (double i = 0; i < 1.0; i += 0.1)
       printf("%0.40f", i);

    return 0;
}
    • 最後の数が、0.9999...で表示された。なんとなく理解したつもり。iostreamではどうやるんだかよくわからず。
    • あんまり浮動小数使わないからハマりそうな予感。気をつけよう。
  • オーバーロードは便利。Cにも欲しいぞ(名前空間が全然違うので無理)
  • 戻り値だけ違うオーバーロードは出来ない。
    • 欲しいだけではダメダメ。

4章 - ポインタ天国

  • ポインタのアドレスを表示したい時はsize_tにキャスト
    • unsignedだと怒られる。
    • printf使ったほうが楽。
  • sizeof arrayは便利なんだけど、sizeof pointerで配列の長さを取得できない。当たり前か。
  • sizeof (int)は括弧必要。sizeof arrayは括弧不要。
  • constは便利。
    • const char array[]なんてこともできるが、スタック上に置かれるので、定数化されるだけで、読み取り専用領域に置かれる訳ではないようだ。

5章 - クラスの前に

  • structの省略は便利。いちいち指定し直す必要が無い。
  • デフォルト引数か。スゲー便利そう。
  • staticはゼロで初期化される。
#include <iostream>
using namespace std;

int main()
{
    static int hoge[10];

    for (int i = 0; i < sizeof hoge / sizeof (*hoge); i++)
        cout << &hoge[i] << " : " << hoge[i] << endl;
}
    • メモリの位置も全然違う事を確認した。
    • ゼロで初期化するのって案外面倒そうなんだけどどうなってんだろう。
  • fill_nで初期化もできる。
  • C++では、mainに対する再帰が出来ないって書いてあったけど、できちゃったり。
#include <iostream>
using namespace std;

int main(void)
{
    static int i = 10;

    if (i) {
        cout << i-- << " ";
        return main();
    }

    return 0;
}
#include <iostream>
using namespace std;

void p(int n)
{
    cout << n;
}

int main(void)
{
    int p = 1;

    ::p(p);

    return 0;
}
    • こら便利。
  • externの解説がすげーわかりやすいな。
  • constは値についてconstするだけで、ポインタは変更可。
#include <iostream>
using namespace std;

int main(void)
{
    const int *i;

    i = NULL;
    // エラー *i = 100;

    cout << i;

    return 0;
}
    • あんまりこういうのはよくないね。
  • 配列のdeleteはdelete []とする。何故なのかイマイチだ。

6章 - クラスの基礎

  • クラスと構造体は大体同じような物。
  • 配列に対しても初期化できるのか。括弧あり、無しがよくわからん。
  • 分割コンパイル(2)の説明がわかりづらいな。
  • コピーコンストラクタか。イマイチ謎だった部分が解けた気がする。C++はやっぱメンドイな。
    • オブジェクトなのに値渡し。
    • Cの構造体で試すと
#include <stdio.h>

struct Point
{
    int x;
    int y;
};

void test(struct Point p)
{
    printf("%p\n", &(p.x));
}

int main()
{
    struct Point p;

    printf("%p\n", &(p.x));

    test(p);
}
    • ホントだ。構造体の値渡しなんてやったことなかった・・・。
  • constメンバ関数か。!の代わりにconstを付けると。ナルホドナルホド。

7章 - クラスの本領

  • 継承についての話。書いてないので後で書くかな。
  • ナンダコレ。int a(3);

8章 - ファイルとストリーム

  • ストリームのマニピュレータはやっぱりフクザツ。
    • 小数の表示桁数の変更はcout << setprecision(40) << 0.1;
  • 名前空間は色々ハマリポイントあり。
  • ヘッダではusing namespaceを避ける事。

9章 - テンプレート

  • 関数テンプレートではデフォルト引数を取ることが出来ない。

10章 - エラー処理と例外

  • ラベルの後には文が必要。
    • おぉ知らなかった。goto結構使うので ← ダメプログラマ

ちと疲れてきたので、自習課題

浮動小数を2進表記せよ。

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    double x = 0.1;
    int k = (int) (log(x) / log(2));
    double p;

    x *= pow(2.0, (double) -k);

    cout << "2 ^ " << k + 1 << " * 0.";

    for (int i = 0; i < 52; i++) {
        x = modf(x, &p) * 2;
        cout << p;
    }
}

/*
2 ^ -2 * 0.0110011001100110011001100110011001100110011001100110
*/

指数部を抜いて、2倍すればビットシフトできるので、modfしながら1ビットづつ切り出していく。

浮動小数点数 - Wikipediaを見ると、指数部はちょっと面倒そうなので略。

まだおかしい所がいっぱいあるな。ゼロ以下には対応してないし、logを使ってるので正確な値が出てるかどうかも不明。

マイナスは符号を取ればいいとして、log(0)が問題だ。浮動小数の指数部を正確にゲットしたい時はどうすればいいんだろう。


正確には、浮動小数ではなくて浮動小数点数か。

union 使えば ALL OK?

浮動小数点数の2進数表示 - 好き勝手に・げーあにん?

おぉぉぉ。unionスゲー。

ということで修正。

#include <cstdio>

void double_dump(double x)
{
    union {
        double d;
        unsigned long long ll;
    } u;

    u.d = x;

    printf("%0.5f %16lx : ", u.d, u.ll);

    int i = 63;

    printf("%s", (u.ll >> i--)? "- " : "+ ");

    for (;i != 0; i--) {
        printf("%d", (u.ll >> i) & 1);
        if (i == 52)
            printf(" .");
    }
    printf("\n");
}


int main()
{
    double_dump(5);
    double_dump(3);
    double_dump(2);
    double_dump(1);
    double_dump(0);
    double_dump(1.0/2);
    double_dump(1.0/3);
    double_dump(1.0/5);
    double_dump(1.0/7);

    double_dump(-1);

    return 0;
}

/*
5.00000 4014000000000000 : + 10000000001 .010000000000000000000000000000000000000000000000000
3.00000 4008000000000000 : + 10000000000 .100000000000000000000000000000000000000000000000000
2.00000 4000000000000000 : + 10000000000 .000000000000000000000000000000000000000000000000000
1.00000 3ff0000000000000 : + 01111111111 .000000000000000000000000000000000000000000000000000
0.00000                0 : + 00000000000 .000000000000000000000000000000000000000000000000000
0.50000 3fe0000000000000 : + 01111111110 .000000000000000000000000000000000000000000000000000
0.33333 3fd5555555555555 : + 01111111101 .010101010101010101010101010101010101010101010101010
0.20000 3fc999999999999a : + 01111111100 .100110011001100110011001100110011001100110011001101
0.14286 3fc2492492492492 : + 01111111100 .001001001001001001001001001001001001001001001001001
-1.00000 bff0000000000000 : - 01111111111 .000000000000000000000000000000000000000000000000000
*/

がっつり2進数でました。アリガトウございます。

1, 2, 0.5がゼロだ。なんでゼロなんだ!?と思ったら、倍精度 - Wikipedia

指数部の値から指数部バイアスを引いた値となる。

指数部を引けば指数分余裕が出るので、精度を上げることが出来るという工夫らしい。ナルホド。

11章 - もっと高く

  • 代入の話が出てきたので、swapが短く書けるのでは!?と思い、
void swap(int& a, int& b)
{
    a ^= b ^= a ^= b; // うまく動かず。
}
    • bはうまくswapしてくれるんだけど、aが0になってしまう。代入前の参照には元の値が入ってるみたいだ。
    • コレはうまくいく。
int main()
{
    int a = 1, b = 2;

    a ^= b ^= a ^= b; // うまくいく

    cout << a << " " << b << endl;
}
    • どうやら値に展開されるタイミングの問題っぽい。
  • 演算子はかなり使えそうな予感!!

12章 - もっともっと高く

  • ちょっとこの本を甘く見すぎてたみたいだ。結構深いぞ。
  • マクロの話がかなり詳しい。

13章 - もっと深く

  • 多重継承とかインターフェイスとか。
  • だいぶ重要な所も詰まっているので、後で写経しよう。

14章〜

  • Cと共通する部分が多いのでガガーっと読み流す。
  • unionについての技も書いてあった
    • unionってそう使うのかww

ということで

まだ理解してない所もあるけど、一応読了。


かなり知らないこともあり、新鮮な発見が出来ました。C++って深いなぁ。と感じさせてくれる良書でした。


もう一度キッチリ読んでから次のステップへ進みたいと思います。


次のステップも書いてあるんですが・・・C++の本は高い・・・。