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

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

c++のお勉強~その2~

一歩ずつ!

型・インスタンス・オブジェクト

構造体は型、型を使って作られた変数はインスタンス。特に、構造体は意味のある情報の塊なので、構造体変数のことをオブジェクトということがある。

アクセスの仕方:①オブジェクト.メンバ ②オブジェクトのポインタ->メンバ

列挙型

何らかのフラグを宣言するときによく用いられる

enum ResultFlag{
  Success = 1,
  Failure = 0
}

三項演算子

a > b ? a : b 真ならばa、偽ならばb

静的変数

プログラムが実行される前にすでに位置がきまっている変数のこと。グローバル変数は静的変数。

初期化はローカル変数であっても一度しか行われない。関数を抜けても値が保存される。

スコープ

::をつけるとグローバル関数にアクセスできる

#inculde <iostream>

int a = 1;
int main(){
  std::cout<< ::a << std::endl;
} 

メモリの動的確保

newとdeleteはセット。newでメモリを動的に確保でき、ポインタで受ける。

int *p = new int;
*p = 0;
cout << *p << endl;

delete p;

配列

int *array;
cin >> size;
array = new int[size]

delete[] array;

ポインタ

アドレスを入れることのできる変数

ポインタと参照の違い

参照は初期化時に一度参照を決めたら変更できないのに対し、ポインタは再代入すれば何度でも書き換えることが可能。その代わりポインタは*をつけないと参照先のメモリにアクセスできない。

const

ポインタや参照の前にconstをつけると参照先の値の変更ができなくなる。

int StrCount(char* str, char ch){
 if (str[i] = ch)
 < contents > 
} //書き換わってしまう

int StrCount(const char* str, char ch){
 if (str[i] = ch)
 < contents > 
} //書き換わらない

本来はstr[i] == chとしたかったので、constとするとエラーにより気づくことができる

const char* p //参照先の値が定数
char* const p = &a //ポインタpが定数
const char* const p = &a //両方定数

 コピーコンストラクタ

参考: コピーコンストラクタ

初期化と代入の違い

b = a ; //代入 コピーコンストラクタが呼ばれない
intArray b = a; //初期化->コピーコンストラクタ
intArray b(a); //初期化->コピーコンストラクタ

継承

privateは派生クラスにさえ公開されない。派生クラスにのみ公開する場合はprotectedにする。

基底クラスからコンストラクタが呼ばれ、派生クラスからデストラクタが呼ばれる。

基底クラスのコンストラクタに引数を持つ、派生クラスのコンストラクタを呼ぶときは以下のように指定する。

コンストラクタ(仮引数リスト) : 基底クラス名(実引数のリスト) , メンバ変数(初期化の値)
{
...
}

補足:基本の方であってもコンストラクタを持っている

int x(3);
int x = 3;

参考:

C++の基礎 : 継承

アップキャスト

派生クラスのオブジェクトは基底クラスへの参照に渡すことができ、この暗黙のキャストをアップキャストという。

オーバーライド

同じ形の関数を派生クラスで再定義することをオーバーライドという。virtualをつけるとアップキャストしても派生クラスのメンバ関数が呼ばれる。

class hoge{
  public:
    virtual bool Set();
};

オーバーライドとアップキャストなどで得られる性質をポリモーフィズムという

純粋仮想関数

protected:
  virtual void HogeBase() = 0

のようにvirtual ~ =0とすると純粋仮想関数になる。これが含まれているクラスは抽象クラスとよばれ、オブジェクトが作れない。

テンプレート

テンプレート引数、実引数

templete <typename TYPE> // <- テンプレート引数
 void Test(TYPE* num, TYPE value)
{
 int a = 1
}

Test(0.1 , 0) //コンパイルエラー ∵double か intかわからない
Test<double>(0.1 , 0) // <-テンプレート実引数

テンプレートクラス

templete <typename TYPE> class Array{...}

int Array::Size() const{...} // コンパイルエラー ∵Arrayはクラステンプレートでクラスではない

int Array<int>::Size() const{...} //テンプレート引数をもって初めてクラスになる
int Array<double>::Size() const{...} //テンプレート引数をもって初めてクラスになる
//↓
templete <typename TYPE> 
  int Array<TYPE>::Size() const {...} //テンプレート引数をもって初めてクラスになる

エラー処理

try {
  if (エラー判定処理){
     throw エラーメッセージ;
   }
}catch(変数宣言){
 エラー処理
  }

throwなどで投げれれた例外は伝播するので、関数内で発生してもそれを用いている上位でtry catchがあれば、処理される。

例外のキャッチ漏れが無いように注意しよう。

例外の再送出

try{
 throw "エラー発生"
catch(...){
 //したい処理をする
 throw;
}

例外はアップキャスト可能

できる限り、基底クラスから離れた例外でcatchするようにしよう。

Exceptionへの参照のキャッチはできる限り使わない。ex:OpenFileExceptionなど基底クラスから離れたものを使う。

参考: ロベールのC++教室 - 第15章 アップキャスト -

メンバ初期化子

参考: メンバ初期化子 - ぷろみん

ロベールのC++教室 - 第22章 メンバ定数 -

イテレータ

イテレータとは?|C++ フリーでぷろぐらみんぐさんから抜粋。わかりやすい。

#include <cstdlib>
#include <iostream>

  vector<int> vec;
  vector<int>::iterator i;
  int sum = 0;

  vec.push_back(1);
  vec.push_back(2);
  vec.push_back(3);

  for(i=vec.begin(); i!=vec.end(); ++i){
    sum += *i;
  }

  cout << sum << endl; // 6

参考: C++ iterator 入門

c++ - イテレータとポインタの違い - スタック・オーバーフロー

イテレータとは?|C++ フリーでぷろぐらみんぐ