[C++] 循環参照

クラスの相互参照における問題
A.h

#ifndef _A_H_
#define _A_H_

#include "B.h"

class A {
    B* m_bB;
    ...
}

#endif // _A_H_

ifndef, define, endifは重複回避

B.h

#ifndef _B_H_
#define _B_H_

#include "B.h"

class B {
    A* m_bA;
    ...
}

#endif // _B_H_

お互いに参照していると、いつまで経っても参照が終わらなくなってしまう

#ifndef _A_H_
#define _A_H_

class B;

class A {
private:
    B* m_bB;
public:
    A();
    void foo();
    void bar();
    ...
}

#endif // _A_H_
#ifndef _B_H_
#define _B_H_

class A;

class B {
private: 
    A* m_bA;
public:
    B(A* pA);
    void hoge();
}

#endif // _B_H_

includeはしていないのだが、うーん、なんかよくわからんな…

[C++] for文のautoの書き方

std::vector<int> v;

for(std::vector<int>::const_iterator it = v.begin(), e=v.end(); it != e; ++it){
    std::cout << *it << std::endl;
}

c++11の範囲for文を使うと以下のように書ける

std::vector<int> v;

for(const auto& e: v){
    std::cout << e << std::endl;
}

### 範囲for文(range-based for statement)
配列やコンテナなど複数の要素を持つものから、全ての要素に含まれる値を取り出して処理する

#include <iostream>
using namespace std;

int main() {
    int a[] = {1, 2, 3, 4, 5};
    int sum = 0;
    for(int x : a){
        sum += x;
    }
    cout << "sum = " << sum << end;
    return 0;
}

vector要素の出力

    vector<string> v(5);
    for (int i = 0; i < v.size(); i++){
        string& x = v[i];
        cin >> x;
    }

autoは型推論を行うキーワード

    vector<string> v(5);
    for (auto& x : v){
        cin >> x;
    }

[C++] ヘッダとソースでファイルを分ける

C++ではクラスの定義とそのメンバ関数の定義をヘッダファイルとソースファイルで分割するのが一般的である

### ファイルを分割していない例
c.hpp

#ifndef C_HPP
#define C_HPP

class c {
    private:
    int m_value;

    public:
    int get() {
        return m_value;
    }

    void set(int const value){
        m_value = value;
    }
};

#endif

### ファイルを分割した例
c.hpp

#ifndef C_HPP
#define C_HPP

class c {
    private:
    int m_value;

    public:
    int get();

    void set(int const value);
};

#endif

c.cpp

#include "c.hpp"

int c::get(){
    return m_value;
}

void c::set(int const value){
    m_value = value;
}

インラインで書くこともある

#ifndef C_HPP
#define C_HPP

class c {
private:
int m_value;

public:
int get();

void set(int const value);
};

inline int c::get(){
return m_value;
}

inline void c::set(int const value){
m_value = value;
}

#endif

bitcoinのソースコードで、基本hppとcppのファイル構造になっていたが、謎が解けた。

[C++].hppとは

### .hppとは
ヘッダーファイルで.hpp、.hというファイル形式で保存
.hppはc++が入っている。.hはc言語だがc++でも使用できる

sample.hpp

#ifndef Sample_hpp
#define Sample_hpp

#include <iostream>

using namespace std;

class Sample {
    public:
        string name;
};

#endif

SRM464 ColorfulBoxesAndBalls

You are playing a game where you have numRed red boxes, numBlue blue boxes, numRed red balls, and numBlue blue balls.

You must place a single ball into each box. Each box is then scored as follows:
If the box is red and it contains a red ball, you get onlyRed points.
If the box is blue and it contains a blue ball, you get onlyBlue points.
In all other cases, you get bothColors points.
Your total score is the sum of the scores of all the boxes.

Return the maximum possible total score you can get.

#include <algorithm>
#include <limits.h>
using namespace std;

class ColorfulBoxesAndBalls {
    public:
        int getMaximum(int numRed, int numBlue, int onlyRed, int onlyBlue, int bothColors){
            int ans = INT_MIN;
            int change = min(numRed, numBlue);

            for(int i =0; i <= change; i++){
                int myscore = (numRed - i) * onlyRed
                    + (numBlue - i) * onlyBlue
                    + 2 * i * bothColors;
                ans = max(ans, myscore);
            }
            return ans;
        }
};

max値をfor文で回して、全パターンの最大値を検索するアルゴリズム
数が少ない方をchangeと定義するのがみそ

C++ 入門の入門1

わざとエラーを発生させる

#include <iostream>
using namespace std;

int main(){
    cout << "hello world\n"
}

void main(){
    cout << "hello world\n";
}

### コンパイルオプション
オブジェクトファイル -c
実行ファイル -o
静的ライブラリをリンク -L
ヘッダを追加 -l
警告 -W, -wall
機能有効 -std=c++11
最適化 -O

#### 変数

int main(){
    int a = 12345;
    int b = 98765;
    cout << a + b << endl;
    cout << a - b << endl;
}

intは32bit

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

int main(){
    cout << numeric_limits<int>::lowest() << ", " << numeric_limits<int>::max() << endl;
}

floatが32ビットだがdoubleは64bit

int main(){
    double a = 1.23;
    double b = 5.43;
    cout << a * b << endl;
    cout << a / b << endl;
}

[C++] ファイルの入出力

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


int main() {
    
    ofstream fout("test0.txt");
    if(!fout){
        cout << "ファイルをオープンできませんでした。\n";
        return 1;
    }
    else
        cout << "ファイルをオープンしました。\n";

    fout.close();
    cout << "ファイルをクローズしました。\n";

    return 0;
}

ファイル出力

    fout << "Hello\n";
    fout << "Goodbye\n";
    fout << "ファイルに書き込みました。\n";

### 書式を設定してファイル出力

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;


int main() {
    
    ofstream fout("test0.txt");
    if(!fout){
        cout << "ファイルをオープンできませんでした。\n";
        return 1;
    }
    else
        cout << "ファイルをオープンしました。\n";

    const int num = 5;
    int test[num];
    cout << num << "人の点数を入力してください。\n";
    for(int i=0; i<num; i++){
        cin >> test[i];
    }

    for(int j=0; j<num; j++){
        fout << "No." << j+1 << setw(5) << test[j] << '\n';
     }

    fout.close();

    return 0;
}

### ファイルから入力

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


int main() {
    
    ifstream fin("test0.txt");
    if(!fin){
        cout << "ファイルをオープンできませんでした。\n";
        return 1;
    }

    char str1[16];
    char str2[16];
    fin >> str1 >> str2;
    cout << "ファイルに書き込まれている2つの文字列は\n";
    cout << str1 << "です。\n";
    cout << str2 << "です。\n";

    fin.close();

    return 0;
}
int main() {
    
    ifstream fin("test0.txt");
    if(!fin){
        cout << "ファイルをオープンできませんでした。\n";
        return 1;
    }

    const int num = 8;
    int test[num];
    for(int i=0; i<num; i++){
        fin >> test[i];
    }

    int max = test[0];
    int min = test[0];
    for(int j=0; j<num; j++){
        if(max < test[j])
            max = test[j];
        if(min > test[j])
            min = test[j];
        cout << "No." << j+1 << setw(5) << test[j] << "\n";
    }

    cout << "最高点は" << max << "です。\n";
    cout << "最低点は" << min << "です。\n";

    fin.close();

    return 0;
}

$ g++ -o sample sample.cpp && ./sample
No.1 80
No.2 68
No.3 22
No.4 33
No.5 56
No.6 78
No.7 33
No.8 56
最高点は80です。
最低点は22です。

### コマンドライン引数

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


int main(int argc, char* argv[]) {

    if(argc != 2) {
        cout << "パラメータの数が異なります。\n";
        return 1;
    }
    
    ifstream fin(argv[1]);
    if(!fin){
        cout << "ファイルをオープンできませんでした。\n";
        return 1;
    }

    char ch;
    fin.get(ch);

    while(!fin.eof()){
        cout.put(ch);
        fin.get(ch);
    }

    fin.close();

    return 0;
}

### practice

int main() {

    for (int i=1; i<=30; i++){
        cout.width(3);
        cout.fill('-');
        cout << i;
        if(i % 5 == 0) {
            cout << "\n";
        }
    }

    return 0;
}

$ g++ -o sample sample.cpp && ./sample test0.txt
–1–2–3–4–5
–6–7–8–9-10
-11-12-13-14-15
-16-17-18-19-20
-21-22-23-24-25
-26-27-28-29-30

#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;


int main(int argc, char* argv[]) {
    
    ifstream fin(argv[1]);
    if(!fin){
        cout << "ファイルをオープンできませんでした。\n";
        return 1;
    }

    const int num = 8;
    int test[num];
    for(int i=0; i<num; i++){
        fin >> test[i];
    }

    int max = test[0];
    int min = test[0];
    for(int j=0; j<num; j++){
        if(max < test[j])
            max = test[j];
        if(min > test[j])
            min = test[j];
        cout << "No." << j+1 << setw(5) << test[j] << "\n";
    }

    cout << "最高点は" << max << "です。\n";
    cout << "最低点は" << min << "です。\n";

    fin.close();

    return 0;
}

[C++] マニピュレータ

入出力の書式に関する定義をmanipulatorという

int main() {
    
    cout << "こんにちは!" << endl;
    cout << "さようなら!" << endl;

    return 0;
}

10進数以外の出力

int main() {
    
    cout << "10を10進数で表記すると" << dec << 10 << "です。\n";
    cout << "10を8進数で表記すると" << oct << 10 << "です。\n";
    cout << "12を8進数で表記すると" << 12 << "です。\n";
    cout << "10を16進数で表記すると" << hex << 10 << "です。\n";

    return 0;
}

$ g++ -o sample sample.cpp && ./sample
10を10進数で表記すると10です。
10を8進数で表記すると12です。
12を8進数で表記すると14です。
10を16進数で表記するとaです。

出力幅指定

int main() {
    
    for(int i=0; i<=10; i++){
        cout << setw(3) << i;
    }
    cout << '\n';

    return 0;
}

[C++] ストリーム

int main() {
    
    int i;
    double d;
    char str[100];

    cout << "整数値を入力してください。\n";
    cin >> i;
    cout << "小数値を入力してください。\n";
    cin >> d;
    cout << "文字列を入力してください。\n";
    cin >> str;

    cout << "入力した整数値は" << i << "です。\n";
    cout << "入力した小数値は" << d << "です。\n";
    cout << "入力した文字列は" << str << "です。\n";
    

    return 0;
}

1文字入出力関数

int main() {
    
    char ch;

    cout << "文字を続けて入力してください。\n";

    while(cin.get(ch)){
        cout.put(ch);
    }

    return 0;
}

出力はばの固定

int main() {
    
    for(int i=0; i<=10; i++){
        cout.width(3);
        cout << i;
    }
    cout << "\n";

    return 0;
}

フィル文字指定

int main() {
    
    for(int i=0; i<=10; i++){
        cout.width(3);
        cout.fill('-');
        cout << i;
    }
    cout << "\n";

    return 0;
}

数値の精度

int main() {
    
    double pi = 3.141592;
    int num;

    cout << "円周率を出力します。\n";
    cout << "有効桁数何桁で出力しますか?(1~7)\n";
    cin >> num;

    cout.precision(num);

    cout << "円周率は" << pi << "です。\n";

    return 0;
}

書式状態フラグ
L 左寄せで出力

int main() {
    
    cout.setf(ios::left, ios::adjustfield);
    for(int i=0; i<=5; i++){
        cout.width(5);
        cout.fill('-');
        cout << i;
    }
    cout << '\n';
    cout.unsetf(ios::left);
    cout.setf(ios::right, ios::adjustfield);
    for(int j=0; j<=5; j++){
        cout.width(5);
        cout.fill('-');
        cout << j;
    }
    cout << "\n";

    return 0;
}

[C++] 例外処理

int main() {
    
    int num;
    cout << "1~9までの数を入力してください。\n";
    cin >> num;

    try {
        if(num <= 0)
            throw "0以下を入力しました";
        if(num >= 10)
            throw "10以上を入力しました";
        cout << num << "です。\n";
    }
    catch(char* err) {
        cout << "エラー:" << err << "\n";
        return 1;
    }
    return 0;
}