随時更新予定
個人的分からなくて壁にぶち当たった部分を理解したつもりで書いてるだけなのでもし間違っているところとかありましたら教えていただけると幸いです。
関数
#define
C言語におけるプリプロセッサ指令(コンパイルの前に前処理を行うプログラム)
マクロと呼ばれ、直訳すると定義という意味になる
プログラム上で固定値であり続ける定数もここで定義してしまえばいい
#define PI 3.141592654
↑のように、定数の宣言をする。使い方は通常の変数と一緒でPIと書くだけで3.1415...の代入された値を用いることができる
更に、#defineを用いて関数を定義することもできる
#define area(r) (PI*r*r)
↑のように、#defineの後に関数名と(引数)を宣言して、その後の()内に処理を書く
#defineにおいては引数に型の宣言がいらず、retrunで値を返す必要がない
そのうえで、近年ではconstexprを用いる事が増えている
constexpr
「constant expression (定数式)」の略語
#defineがコンパイル前にしか処理を行えなかったのに対し、記入されたものを判断してコンパイル前にできれば、コンパイル前に、できなければ後に自動的に切り替えて処理してくれる
ただし、こちらは型の宣言が必要
typedef
既存のデータ型に新しい名前を付けるための宣言
typedef int age;
↑これで新たにageというint型と同じ型をもつデータ型を作れる
さらに配列のデータ型も作れる
typedef int num[5];
num first={1,2,3,4,5};
↑というようにわざわざ毎回配列の型で宣言しなくてもよくなる
構造体
クラスと似てはいるが、public privateを無記入の場合のデフォルトが違う
使い分けとして変数のみを扱うなら構造体、関数まで取り扱うならクラスにするとよい
複数のデータ型を寄せ集めて1つのデータ型として扱うことができる
struct Human
{
char name[10];
int age;
char gender; //0:男 1:女
}
↑このように宣言ができる
structは構造体を定義するための宣言
構造体内で定義された変数をメンバ変数と呼ぶ
struct Human achan = { "A子", 19, 1 };
struct Human bkun = { "B太", 20, 0 };
↑このように定義された構造体を用いて変数を作ることができる
また、構造体変数からメンバ変数にアクセスする方法もある
struct Human achan;
ayane.name = "A子";
ayane.age = 19;
ayane.gender = 1;
↑このようにすればよい
更に、構造体は配列で使用することもできる
struct Human friend[] =
{
{ "A子", 19 , 1 };
{ "B太", 21 , 0 };
{ "C太", 19 , 0 };
{ "D子", 19 , 1 };
}
構造体とtypedef
構造体とtypedefを組み合わせることでもっと便利になる
typedef struct Human
{
char name[10];
int age;
char gender;
}
↑このようにすることで複数の型を寄せ集めた完全に新しい型を作ることができる
利用するにも
Human achan = { "A子", 19 , 1 };
だけでよくなり、毎回structを入力する必要がなくなる
enum
列挙型という配列のように複数の値を同時に保持できるもの
enumの特徴は、保持している要素にそれぞれ順番に値が付与されるということ
enum State
{
idol = 0, //ここが基準の数値になる
walk, //1
run, //2
dying = 10, //途中から数値の基準を変える事もできる
die //11
};
知識
nullとnullptr
C# null
C++ NULL or nullptr
NULL→定数NULLとして実行時に0で初期化される←使用が推奨されていない
nullptr→厳密に何が入っているかは明確じゃないけど、nullが入っている
定数定義系の定義タイミング
constexpr
コンパイル時に定義するもしコンパイル時にできなかったらexe実行時に定義する(コンパイル時には不定な数値があることがある)←今の流行り
const
exeファイルを実行する時に定義する
#define
コンパイル時に定義する
アロー演算子とドット演算子
どちらも構造体のメンバー(要素)にアクセスするために必要
細やかな部分は理解していなくても下記さえ理解していればとりあえず大丈夫っぽい
struct list_data {
string name;
int age;
};
アロー演算子
->
構造体を指す変数がポインタ変数であるならアロー演算子
list_data *listPtr; //構造体を指すポインタ
string leader
leader = listPtr -> name;
ドット演算子
.
構造体を指す変数がただの変数であるならドット演算子
C#ではポインタの概念が存在しないのでこちらしか使わない
list_data listData; //構造体を指すポインタ
string leader
leader = listData.name;
ファイルを分けてプログラミングする
C++でのプログラミングは主にソースファイル(.cpp)とヘッダファイル(.h)によって構成される
それぞれ違う役割を持っている
ソースファイル
ヘッダファイルで用意した関数の処理内容を記述する
ヘッダファイル
必要な関数のプロトタイプ宣言をする
基本的にはソースファイルとヘッダファイルは対になってワンセットとして使用する
Player.cppとPlayer.hのように同じ名前に拡張子だけ違うという状態で命名するのが基本
Player.hでプロトタイプ宣言した関数はPlayer.cppで処理を記述する
ただし、色々な処理をまとめて実行するファイルだけは別で用意する必要がある
よっぽどこだわりがなければ、命名はMain.cpp等になる
Main.cppには対になるヘッダファイルは無く、Main.cppにはプロジェクトのセッティングの処理(ウィンドウサイズ等)以外は記入しないようにする
それぞれのソースファイルで処理を記入した関数はMain.cppでヘッダファイルをインクルードして呼び出すことで処理する
コンストラクタとデストラクタ
class SQUARED {
public:
int num;
//コンストラクタ
SQUARED(int tmp) {
num = tmp * tmp;
}
//デストラクタ
~SQUARED() {
cout << "デストラクタ実行" << endl;
}
};
int main() {
//SQUAREDクラスのポインタを宣言
SQUARED* sqrt;
//クラスの動的確保
//このタイミングでコンストラクタが実行される
sqrt = new SQUARED(2);
cout << sqrt->num << endl;
//メモリを開放する
//このタイミングでデストラクタが実行される
delete sqrt;
return 0;
}
コンストラクタはオブジェクトの生成時に、デストラクタはオブジェクトの破棄時に実行される関数
書き方は両方とも絶対にクラス名と同じ名前で、デストラクタのみ名前の前に~(チルダ)を用いる
コンストラクタでは主にそのオブジェクトの初期化を行い、デストラクタでメモリの開放を行う
class Human{
private:
int age;
public:
Human(int age);
}
int main(){
Human human(20);
}
上記のようにコンストラクタはオブジェクトの生成時に引数を渡してあげることができる
constの位置とその効果
constはその変数の値を不変にさせるものだが、ポインタ型で使用する場合においては、constを書く位置によって不変になる場所が大きく変わる
普通のconst
const int num = 10; //numは10で初期化されて書き換えることはできない
int const hoge = 15; ///hogeも15で初期化されて書き換えることはできない
num = 20; //エラー
このようによくあるような使い方の場合は型の前に書いても後ろに書いても同じ意味になる。
const *
int num = 0;
//constとintの位置はどちらでも同じ
const int* hoge = #
int const* hogehoge = #
hoge = # //OK
*hoge = 10; //エラー
このように、const
の後ろ(右側)に*
がある場合ポインタが指す実体を変更することができない
そのため、ポインタ変数そのものを指すhoge
にnumのアドレス
を代入するのは大丈夫だが、
ポインタ変数であるhoge
を用いてhoge
が指す値自体を数値で上書きするとエラーになる
* const
int num = 0;
int *const hoge = #
hoge = # //エラー
*hoge = 10; //OK
このように、const
の前(左側)に*
がある場合ポインタ変数そのものを変更することができない
そのため、ポインタ変数そのものであるhoge
に代入しようとするとエラーになる
だが、hoge
のポインタに値を入れる分にはエラーにならない
const* const
int num = 0;
const int *const hoge = #
hoge = # //エラー
*hoge = 10; //エラー
このように、const
が*
を挟む形の場合ポインタが指す実体もポインタ変数自体も変更することができない
const
の前にも後ろにも*
があるため、その両方の性能を兼ね備えた効果がある
ポインタを使うタイミング
typedef struct {
int Image; //グラフィックハンドル
int PosX; //X座標
int PosY; //Y座標
bool Dir; //向き(FALSE:正方向|TRUE:反転)
float Speed; //速度
} Player_t;
// 初期化をする
void Initialize(Player_t* Player, int PosX, int PosY);
// 動きを計算する
void Update(Player_t* Player);
// 描画する
void Draw(Player_t Player);
// 終了処理をする
void Finalize(Player_t Player);
上記のソースにおいてInitialize(),Update()の引数にはPlayer_t*型を利用しているのに対して、
Draw(),Finalize()ではPlayer_t型を引数として指定している
この違いは、これらの関数の呼び出し先ですることによって変わる
上2つ
はPlayer_tのメンバ変数に対して書き込む処理をするため、ポインタに書きこむ必要がある
下2つ
はPlayer_tのメンバ変数を使用したいだけなので、直接構造体から参照すればいい
ということ
ストラテジー(デザインパターン)とは
class Shape {
public:
virtual calculation calc() = 0; //calcはインターフェース
};
class Circle : public Shape {
public:
calculation calc() override;
};
class square : public Shape {
public:
calculation calc() override;
};
int main(){
calculation* tmpCalc = new Circle();
tmpCalc->calc();
}
main部はCircleのインスタンスを生成していますが、保持の仕方としては、抽象クラスのポインタで保持している
こうすることで、Squareに切り替えたい時は
= new Circle();
を
= new Square();
にするだけで本体の部分は全く変更する必要がない
ということだが、よく分かってない
座標変換の順番
拡大、回転、移動の順
単語
オーバーロード
同じ関数名でちがう引数のもの
コールバック
何かしらイベントが発生したときに呼ぶ関数
リンク
すべての2進数に変換されたファイルをまとめてexeファイルにする
コンパイル
プログラム(英数字で書かれたもの)を0と1に変換する工程
アドレス
変数などが格納されるPCのメモリ(保存領域)における住所
&変数名
でその変数のアドレスを取得できる
ポインタ
アドレスを扱う変数のこと
int *変数名
でint型のアドレスをポインタとして扱うことができる
この変数をポインタ変数という
ポインタを利用して変数を変更すると、メモリ自体の中身が書き換えられるため、関数を跨いでも同じ処理ができる、関数を跨いでもそのメモリの場所さえわかればローカル変数でもアクセスできる
スコープ
変数を呼び出せる範囲のこと
それぞれどの範囲に有効な状態で宣言されたかで変数の呼び方が変わる
いらないスコープはつけない
そのスコープ内でしか使わない変数はそのスコープ内でしか使えなくする
グローバル変数
{}で囲まれた処理の外で宣言された変数
インデントが一番下がっているもの
基本的にはそのソースファイル内のどこでも利用できる
ローカル変数
{}で囲まれた処理の中で宣言された変数
その変数が宣言された{}が閉じるまでなら利用できる
コンストラクタ
クラスを動的確保(インスタンスを生成)した時に実行される関数
具体的期にはnew演算子で動的確保されたときに実行される
デストラクタ
メモリが解放されたタイミングで実行される関数
具体的にはdelete関数が実行されたときに実行される
constメンバ関数
そのメンバ関数内で値を変更しない場合、予期せぬエラーを防ぐ目的と、エラーが出たときに、その関数内では値を書き込んでいないため、確認する手間を省ける
class SystemMain final
{
public:
void main() const;
};
このように、メンバ関数のプロトタイプ宣言の時にconstを後ろに付けるだけ
抽象クラス
実装を持たない何をするでもない特殊なクラス
プロトタイプ宣言のみをし、このクラスを親クラスとし、子クラス(派生クラス)と結びつけることで意味を帯びるクラス
オーバーライド
機能の上書きのことらしいが、よく分からない
定義された関数の枠組みだけ利用して、中身を書き換えるということなのかな?
インターフェース
名称、戻り値、引数のみをもつメソッド
処理すら持たない
クラスに継承させて使うらしいがよくわからん
final関数
これ以上の継承をさせないという宣言
または派生クラスでの仮想メンバ関数のオーバーライドをさせないことを宣言するキーワード
コールバック
引数として他の関数に渡される関数
シングルトン
c++におけるデザインパターンの1つ
実行時にそのクラスのインスタンスが必ず単一になるよう設計するというもの
プログラム上では常に同一のインスタンスを参照するように強制する
端末や概念的に1つしか存在しないもの(マウスやキーボード等)が誤って2つ以上インスタンスを持たないようにするために使う
スタック
プログラミングで用いられるデータの取り扱い方
箱の中にデータを入れていき、上にあるデータから取り出すというもの
エアガンのマガジンみたいな感じ
キュー
プログラミングで用いられるデータの取り扱い方
箱の中にデータを入れていき、下にあるデータから取り出すというもの
コンビニの商品棚みたいな感じ
木(データ構造)
閉路を持たないような連結なグラフ
ここを見ればわかる(説明は難しい)
うさぎでもわかる離散数学(グラフ理論) 第11羽 木・根付き木
主な用途として、必要な値がどこにあるのかを探索する際に効率を上げる事ができる
スマートポインタ
コンストラクタで動的に確保したメモリを、一定の条件を満たしたら宣言なしで自動的に開放してくれるポインタ型
使い方は理解次第追記する
範囲ループ
iを用意する必要がない場合のforとして使える
普通のforより軽い
int array[5]={1,2,3,4,5};
for(auto&& n : array)
{
cout<< n <<endl;
}
↑これの場合、arrayの要素数5をforの()でnに要素番号0つ目から順番に代入していき、事実上のarrayの要素数分のループをする
auto&&は多分javaでいう所の「var」みたいなものだと思う
雑学
C++とC#の違い
両者の違いとして最もよく言われるのがメモリへのアクセスのしやすさだが、C++の大きなメリットとして処理が速いというものがある
これは、C++は記述したコードをそのまま実行する(機械語のままでコンパイル)のに対し、C#はCLRという中間言語を作成したのち、CLR経由でコードを実行するためである
また、C#については描画ライブラリを描画が速いものにすると比較的早く処理できる(openGL)