空飛ぶロボットのつくりかた

ロボットをつくるために必要な技術をまとめます。ロボットの未来についても考えたりします。

C++のお勉強(1)

やりたいこと

C++スキルアップ

教科書

本を書きました。『基礎からしっかり学ぶC++の教科書』 | 配電盤

環境構築

$ sudo apt-get install g++

ビルド方法(単体)

$ g++ Sample.cpp 

or

makefileを以下のように記載し、$ make

Sample: Sample.cpp
    g++ -o Sample Sample.cpp
    ##g++ -std=c++11 -o Sample Sample.cpp

ビルド方法(複数)

$ g++ -c Sample1.cpp -o Sample1.o
$ g++ -c Sample2.cpp -o Sample2.o
$ g++ Sample1.o Sample2.o

or

Sample: Sample1.o Sample2.o
    gcc -o Sample Sample1.o Sample2.o

Sample1.o: Sample1.cpp
    gcc -c Sample1.cpp

Sample2.o: Sample2.cpp
    gcc -c Sample2.cpp

参考:

ヘッダーと.cppを作ってコンパイル

メイクファイルをじわーっと作ってみる

ターミナルでC++のコンパイル - Qiita

デバッグツール

gdbの使い方

  • ビルド時に-gをつけて実行
$ g++ -g -O0 Sample.cpp
  • gdb立ち上げ
$ gdb a.out
  • 使ってみる:ステップ実行
$ break main
$ run
$ next
$ next
...
$ quit

参考:  gcc+gdbによるプログラムのデバッグ 第1回 ステップ実行、変数の操作、ブレークポイント

ポインタ

Sample1

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

class Robot{
  string name;
public:
  Robot(){}
  Robot(string n):name(n){}
  void SetName(string n){
    name = n;
  }
  void Speak() const;
};

void Robot::Speak() const {
    cout << "My name is " << name << "!" <<endl;
}


int main (){

  Robot dora;
  Robot *p2;
  p2 = &dora;
  cout << p2 << endl;
  
  p2->SetName("Atom");  //(*p2).SetName("Atom");
  p2->Speak();   //(*p2).Speak();

  Robot *x;
  x = new Robot;
  x -> SetName("Tetsujin");
  x -> Speak();
  delete x;

  Robot *y;
  y = new Robot("Chappy");
  y -> Speak();
  delete y;

  int i;
  int num;
  string temp;
  Robot *r;
  cout << "Please a number of Robot you want to make."<<endl;
  cin >> num;

  r = new Robot[num];

  for (i =0 ; i<num;i++){
    cout << "Please type robot's name." <<endl;
    cin >> temp;
    r[i].SetName(temp);
  }

  for (i=0;i<num;i++){
    r[i].Speak();
    }

  delete [] r;
}

Sample2

#include <iostream>
using namespace std;

int main(){
  int x = 1;
  int* px = &x;
  int** ppx = &px;
  *px = 10;
  cout << x <<endl;
  cout << **ppx <<endl;
}

10
10

スマートポインタ

メモリリークを自動的に防いでくれる

#include <iostream>
#include <complex>
#include <memory>
using namespace std;

int main(){
  using cpdb = complex<double>;
  
  shared_ptr<cpdb> x = make_shared<cpdb>();
  cout << *x << endl;

  shared_ptr<cpdb> y = make_shared<cpdb>(1.1,2);
  cout << *y << endl;

  shared_ptr<cpdb> z = make_shared<cpdb>(*y);
  cout << *z << endl;
}

継承

#include <iostream>
using namespace std;

class Robot
{
  string name;
public:
  void SetName(string n){name = n;}
  string GetName() const{ return name;}
  void InputData();
  void ShowData() const;
};

void Robot::InputData(){
  cout << "input Name:";
  cin >> name;
}

void Robot::ShowData() const{
  cout << "name:"<<name<<endl;
}

class FRobot : public Robot
{
  int power;
public:
  void SetPower(int p){ power = p;}
  int GetPower() const{ return power;}
  void InputData();
  void ShowData() const;
  int FullPower() const { return power * 10;}
};

void FRobot::InputData(){
  Robot::InputData();
  cout << "input power:"<<endl;
  cin >> power;
}

void FRobot::ShowData() const{
  Robot::ShowData();
  cout << "FullPower is :" << FullPower() << "!!!" << endl;
}

int main()
{
  FRobot f[3];
  string temp;
  int i,sum;

  for (i=0;i<3;i++){
    f[i].InputData();
  }
  cout << endl;

  cout << "display all robot power" << endl;
  for(i = 0; i< 3; i++){
    cout <<"Mark" <<i + 1 << "!"<<endl;
    f[i].ShowData();
    cout << "----------------" <<endl;
  }

  sum = 0;
  for (i = 0 ; i <3 ; i++){
    sum += f[i].FullPower();
  }
  cout << "ALL ROBOT FULL POWER :" << sum <<"!!!"<<endl;
}

参照引数の関数

参照引数の場合、引数にコピーしないため軽量

void func(X& a){...}
or
void func(const X& a)

上は、引数のデータが書き換わる可能性あり

下は、書き換わることを防ぐ

関数の引数の種類

  1. int → void func1 (int x) {}
  2. const int → void func2 (const int x) {}
  3. int& → void func3 (int& x) {}
  4. const int& → void func4 (const int& x) {}
  5. int&& → void func5 (int&& x) {}
  6. const int&& → void func6 (const int&& x) {}
  7. int → void func7 (int x) {}
  8. const int → void func8 (const int x) {}

これだけ考えられるが基本的にはfunc1~4を考えれば良い。

参考:右辺値参照・ムーブセマンティクス - cpprefjp C++日本語リファレンス

テンプレート

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

template <typename T>
void SwitchValue(T& x, T& y){
  T temp = x;
  x = y;
  y = temp;
}

int main(){
  int a = 1;
  int b = 2;
  SwitchValue(a,b);
  cout << a << endl;
  cout << b << endl;

  string c = "1";
  string d = "2";
  SwitchValue(c,d);
  cout << c << endl;
  cout << d << endl;

}

参考:第 4 章 テンプレート (C++ プログラミングガイド)

イテレータ

参考:C++ iterator 入門 C++ イテレータ入門 - プログラミングの教科書を置いておくところ

別名

using uint = unsigned int; //typedef unsigned int uint;
uint x = 0; //  equal unsigned int x = 0

キャスト

#include <iostream>
using namespace std;

int main(){
  int x = 0;
  x = static_cast<int>(1.11);
  cout << x << endl;
  x = (int)1.11;
  cout << x << endl;
  x = int(1.11);
  cout << x << endl;
}

ビット演算

#include <iostream>
using namespace std;

int main(){
  int x = 1;
  int y = 5;
  cout << (y >> 1) << endl; //2
  cout << (y << 1) << endl; //10
  cout << (y >> 2) << endl; //1
  cout << (y << 2) << endl; //20
  cout << (x & y) << endl; //1
  cout << (x | y) << endl; //5
  cout << (x ^ y) << endl; //4
  cout << (~x) << endl; //-2
}

列挙型

#include <iostream>
using namespace std;

int main(){
  enum robots { Atom, Tetsujin, Dora };
  robots x = Tetsujin;
  cout << (x==Tetsujin ? "Mark21": "Mark0")<<endl;
}

静的変数

一度だけ初期化され、その後共有される

以下の例ではstaticがないと、出力は1,1,1になる

#include <iostream>
using namespace std;

int increment(){
  static int x = 0;
  ++x;
  return x;
}

int main(){
  cout << increment() <<endl; //1
  cout << increment() <<endl; //2
  cout << increment() <<endl; //3
}

名前空間

#include <iostream>
using namespace std;

int x;

namespace NAME1{
  int x = 1;
}

namespace NAME2{
  int x = 2;
}

int main(){
  int x = 3;
  cout << x << endl;//3
  cout << ::x << endl;//0
  cout << NAME1::x << endl;//1
  cout << NAME2::x << endl;//2
}

コンテナ

#include <iostream>
#include <complex>
#include <vector>
using namespace std;

int main() {

  using cpdb = complex<double>;
  vector<int> v1;
  v1.push_back(2);
  v1.push_back(3);
  v1.push_back(4);
  v1.push_back(5);

  vector<int> v2(4);
  v2[0]=6;
  v2[1]=7;
  v2[2]=8;
  v2[3]=9;

  vector<int> v3{10,11,12,13};

  for (int i = 0 ; i < v1.size() ;i++){
    cout << v1[i] << endl;
    cout << v2[i] << endl;
    cout << v3[i] << endl;
  }

  v3.pop_back();
  v3.erase(v3.begin() + 1);

  for (int i = 0 ; i < v3.size() ;i++){
    cout << v3[i] << endl;
  }

  vector<int> v4(v1);

  for (int i = 0 ; i < v4.size() ;i++){
    cout << v4[i] << endl;
  }

  vector<cpdb> v5;
  v5.reserve(10);
  v5.emplace_back(1.11,2.0);
  cout << v5.capacity() << endl;
  
  vector<vector<int>> v6{{1,2,3},{4,5,6}};

  cout << v6.size() <<endl;
  cout << v6[0].size() <<endl;
  cout << v6[0][2] << endl;
}

例外

#include <iostream>
using namespace std;

void DoSomething(){
  throw runtime_error("error!");
}

int main(){
  try{
    DoSomething();
  }
  catch (exception& e){
    cerr << e.what() <<endl;
  }
  cout << "Normal Stop.";
}