Machine Morning

機械学習やWebについて学んだことを記録しています。

C++入門

最近競プロを始めたことに伴い、C++を勉強している。自分用のtipsとしてメモを残していく。細かい話は慣れてから再度調べるため、おまじないとして自分に言い聞かせている箇所がある。読者はあまり参考にしない方がいい。

using namespace std;

using namespace std;
cin >> hoge;

これは毎回std::を書かなくていいよう名前空間を宣言しているのだが、できるだけ使用を避けたほうが良い。そうでないと他のモジュールのの名前とぶつかる可能性がある。競プロではよく利用されているがシンプルなプログラムを書くときのみの使用に留めておくのが良い。

ちなみにusing namespace std;を書かないと、

std::cin >> hoge;

などと修飾して書く必要がある。

コンパイル

g++ -o hoge hoge.cpp

hoge.cppをコンパイルしてhogeという名前のファイルとして出力する。

g++ hoge.cpp

としてもコンパイル可能だが、a.outという名前のファイルで出力され、どのファイルをコンパイルしたものかわからなくなるため、g++ -o [output_file] [input_file]を使ったほうが良い。

入出力

# include <iostream>

string hoge;

cin >> hoge;
cout << hoge;

入門の記事では入出力にiostreamを使っている様子が多く見られるが、これはどうやら遅いらしい。

【調べ途中: scanf, printfの使い方を調べる】

# include <cstdio>

string hoge;

scanf("%s", &hoge)
printf("%s\n", hoge)

を使うほうが良い。

文字 意味
%c 一文字 char
%s 文字列 string
%d 10進数 int
%f 浮動小数 float

他にもあるがよく使いそうなものだけ。

クラス

class Car {
    private:
        string name;
    public:
    Car(string s) {
        name = s;
    }
};

クラスの名前と同じ関数がコンストラクタとなる。また、上の書き方ではnameという変数を作ってからsを代入しているが、

class Car {
    private:
        string name;
    public:
    Car(string s): name(s) {
    }
};

と書くことで、変数作成時に同時に値を代入することもできる。

関数

class Car {
    private:
        string name;
    public:
    Car(string s): name(s) {
    }
    void printName() const {
        cout << "この車の名前は" << name << "です。" << endl;
    }
};

まずvoidはreturnによる返り値のない関数の宣言である。関数printName()はクラスに属する関数なのでメンバ関数と呼ばれ、coutで画面に出力しているだけである。また、変数を何も書き換えないため、関数の名前のあとにconstを書いている。

ちなみにprivateとクラスの先頭で宣言しているが、public:の上に記述されたものはすべてprivateとなるため、省略可。

インライン関数

上記のコンストラクタCarとメンバ関数printNameはどちらもクラスの中に書かれているため、インライン関数となっている。インライン関数とはクラスから生成されたそれぞれのオブジェクトすべてが、その関数のコードをオブジェクト自身に持つことである。一方クラスの外に関数を書くことも可能で、この場合オブジェクトから関数を呼び出すと、その関数のポインタが指すメモリに格納されたソースコードを読み関数が実行される。どちらも同じ関数を実行することは可能であるが、クラスの内側に関数を書くとソースコードが増えるため、基本的には外に書く。しかし、インライン関数としてクラスの内側に関数を書くことで、メモリの参照をせず、直接オブジェクトが持つ関数のソースコードを実行し、高速に関数を実行することもできる。高速に呼び出したい関数はインライン関数としてクラスの内側、コンパイル後のソースコードを減らしたい場合はクラスの外側に書くと良い。

class Car {
    private:
        string name;
    public:
    Car(string s);
    void printName() const;
};

Car::Car(string s): name(s) {
    }
void Car::printName() const {
    cout << "この車の名前は" << name << "です。" << endl;
}

また、コンストラクタCarをクラスの外側に移動したため、クラス内のコンストラクタの引数であるsを省略することができる。定義が直後に書かれない場合は、引数の型のみ指定して、名前は省略可。

class Car {
    private:
        string name;
    public:
    Car(string);
    void printName() const;
};

Car::Car(string s): name(s) {
    }
void Car::printName() const {
    cout << "この車の名前は" << name << "です。" << endl;
}

クラスに引数の異なる同名のメンバ関数(*コンストラクタも含む)をいくつ書いても良い。

int main() {
    return 0;
}

本来intで宣言された関数は上のように返り値として整数を返さなければいけないが、C++ではmain関数の最後で自動的にreturn 0;してくれる。したがってまmain関数に限り、return 0;は省略可能である。また、main関数の宣言はintで行うように決められているので返り値がないからといって勝手にvoidなどで宣言してはいけない。