2020/11/21

ここのクラスは早いとこ駆け抜けて早く右辺値参照を触りたいね!

 

1.constメンバー関数

基本的にコンパイラーはメンバー関数を「メンバー変数を変更するかもしれないもの」と見ている。

なので、constインスタンス(中身を変更できないようにしたインスタンス)を作ってそのメンバー関数を呼び出そうとすると(中身を変えるものでなくても)エラーが起きてしまう。関数名とかをパッと見ただけじゃ分からんしね・・・。

 

そんな中登場するのが、constメンバー関数。

これはインスタンスがconstになっていたとしても呼び出すことができるメンバー関数のこと。

宣言方法は普通の宣言の後ろにconstをつけるだけ。

 

class クラス名

{

public:

 戻り値 関数名(パラメータ) const;

}

 

戻り値 クラス名::関数名(パラメータ)const

{処理;}

 

みたいな感じ。

 

そしてちょっと前にオーバーロードをやったけど、constメンバ関数であるか否かでもオーバーロードができる。

この時は引数の型や数が同じでも別に関係ない。単純にそのインスタンスがconstか否かで区別される。

 

mutableを使ったconstインスタンスメンバ関数書替は意味が分からないので今はパスしておきます。

 

 

2020/11/19

あの本また借りたので頑張って読みます。

 

これからは

独習C++を基本的にやりつつ、それが終わったらゲームプログラミングC++に移行したいと思います。

そして、数学物理系は前読んでいたゲームを動かす数学・物理が終わったらゲーム開発のための数学・物理学入門 改訂版を読みたいと思います。

 

1,ラムダ式がやっぱり難しい

改めてラムダ式を見てみたのですが、よくわかりませんでした。

構造は、

(パラメータ) -> 戻り値の型

{

処理};

という感じなのですが、パラメータが良く分からない。

 

本では変数に格納していたのですが、そういうもんなのでしょうか?ちなみに変数は常にautoである必要があるみたいです。(ラムダ式の性質上)

 

そして、ラムダ式においては戻り値の型を省略する場合、コンパイラーがラムダ式の中身から戻り値の型を推論してくれるみたいです。便利。なのか?

 

auto return_void = () { std::cout << "何も返さないラムダ式" << std::endl; };

の場合にはvoidに推論


auto return_int = () { return 42; };

の場合にはintに推論するっぽい。

ただ、複数のreturn文があり、一つでもそれが異なるとエラーになる。

 

なので、そのような場合はreturn文の型を統一させるか、戻り値の型を明記して暗黙の型変換をさせるような必要がある。

 

2,ラムダ式のキャプチャについて学びました

ラムダ式はキャプチャという機能を使うことで、ラムダ式の外側で宣言されている変数のコピーを格納して、ラムダ式の内部で使えるようになる。

 

 

つまり、通常関数内では関数外で宣言された変数ってのは使えない。でもそれをどうにかして取り込むぞ!ってのがこのキャプチャという機能らしい。

 

[変数,変数,…](パラメータ) ->戻り値の型

{処理};

[=,変数,変数,…](パラメータ) ->戻り値の型

{処理};

 

ラムダ式内部でも使いたい変数をの中に列挙することで、コンパイラが自動でコピーしてくれる。

 

例:

int a = 0;

auto lambda = [a]()

{

std::cout << a << std::endl;

}

通常はaは外にあるので使えないけど、キャプチャしているので使える。

そしてこれはコンパイラ時に自動で「コピー」されるので、途中でaに別の値が代入されたとしてもそれは影響しない。

 

キャプチャしたい変数がいっぱいある場合は[=]を使う。

これで、ラムダ式内部で使っている変数をコンパイラ―が自動的にキャプチャしてくれる。これを「デフォルトのキャプチャ」と言ったりする。

 

このコピーしてキャプチャした変数は暗黙的にconstになるから変更できない。

もし変更したいのならmutable指定する必要がある。

 

[変数,変数,…](パラメータ) mutable -> 戻り値の型

{処理};

ただ、これはラムダ式の内部で変更されるだけなので、元の変数は別に変化しない。

例:

int a = 0

auto lambda = [a]() mutable

{

a = 42;

std::cout << a << std::endl;

};

この場合は42が出力されるが、ラムダ式の外で宣言されると0が出力される。当たり前だね。

まあでもmutableはほとんど使わないと言っても良いね。

 

3.参照を取得するキャプチャについて学びました

キャプチャが長いので分けます。

参照ってちょっと前にやって覚えてないなあ復習します。

annkate.hatenablog.com

復習しました。同じアドレスを持つってやつね。

これを取得するキャプチャってのも存在するみたい。

これまでのキャプチャはコピーするだけだったので、もとの変数に影響はなかったけどこの参照を取得するキャプチャはバンバン影響するし、mutable指定をしていなくても変更可能。(元の変数がconst指定されてたら出来ないよ)

 

 使い方はさっきと同じ感じで

 

auto 名前 = [&キャプチャしたいヤツ]()

{};

処理の中で変数を変更すると元の変数にも影響が出る。

 

4.usingがよくわかってない

usingを少し忘れてました。ちょっと前にやったし仕方ない。

usingは型に別名を与える時に使う。

①using integer = int;

②using number = integer;

みたいな感じで。

これをすれば後で型を変更したくなった時でも別名の定義場所(この時は②)を変更すればいいだけなので、最高。

 

5.p121理解度チェックをやってみて

色々と記述方法を忘れているので、復習しよう。

 

・usingの使い方(前述)

usingを使った型を戻り値にした関数を定義するときは

クラス名::usingの型 クラス名::関数名()

{処理};

みたいに書かなければいけない。ここの書き方が難しいので良く復習しておこう。

 

・関数の定義について

クラス内で関数を定義することはほとんどなく、クラスの次辺りに詳細を定義することが多い。

その時は

戻り値 クラス::関数名(){}

みたいな感じで使う。

 

・入出力の使い方について

std::cinの使い方について完全に忘れていた。

std::cin >> 入力したい変数とか;

一行全体の入力は

std::getline(std::cin,入れたい変数);とする。

連続して入れたい場合は

std::cin >> a >> b >> c;みたいにすると良い。

 

感想:第二章のほとんどを忘れていた。特にクラスの定義についてほとんど抜けていたのでこの問題はまた解くことにする。

2020/11/16

C++独習を返してしまったので、C++が出来ない!

というか派遣が忙しくて勉強が全然出来ない。

 

移動の間に見ていたこれ

www.amazon.co.jp

が中々に面白かったので、もう一回借りて読む。多分あと一週間もあれば読む終えるであろう。

 

そしてこれ

www.amazon.co.jp

これがかなりこのブログで良いよ!と勧められていたのでもう一回読んでみる。挫折したけども。

 

 

今のところ独習はラムダ式の所までいったので、そこから先にやるのはテンプレートとか?

今自分に必要なのは

C++の基本的な知識 -40%

独習C++でとりあえず事足りる

 

・ゲームプログラミングに関する数学・物理の知識 -10%

→というか数学の知識 -10%

→物理の知識 -0%

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

 

下から順番にやる。一番上は多分うちの大学にないので秋葉かなんかでゲットしておきたいな~と思ったけど正味な話現実的ではないよな。

 

・ゲームプログラミングに特有な知識 -20%

www.amazon.co.jp

 

多分ゲームプログラミングC++を借りるだろうなぁ。

 

ゲームエンジンアーキテクチャとかも少し気になってるけども多分買うのは難しいだろうな。

 

 

C++の発展的な知識

 

Effective C++をやるか。でもそこまでたどり着けるとは思っていない。

 

 

とりあえず今は

独習C++を終わらせる。

ゲームを動かす数学・物理を読破する。

ゲーム開発のための数学…を進める。(読破は無理かも)

ゲームプログラミングC++を読む。

 

で、余裕があったらEffective C++をやる。恐らく余裕はないと思うので。

Qtについてはほとんど無理だろうな。

ライブラリに関しての勉強は果たしてした方がいいのかどうかちょっとわからんけども、とりあえずUE4とかそういうのはやった方がいいと思うかも。。。

 

とりあえず派遣が忙しいけど、それに慣れないといけない。

2020/11/06

1.メンバー関数の定義方法とか色々復習しました

 

クラスの中に含まれている変数をメンバー変数、関数をメンバー関数とするのはだいぶ前にやった気がします。

そのメンバー関数の定義は

返し値 クラス名::メンバー関数名)()

{

}

となるみたいです。

呼び出しにおいてはクラス名を指定する必要はなく、インスタンスに対して.か->で呼び出します。

このメンバー関数はクラスの一部なので、メンバー関数からは非公開メンバー変数や他の非公開メンバー関数にドット演算子を使わずに直接アクセスすることができます。

ゲッターとかセッターとかがそれにあたるかも。

 

getterはそのままメンバー変数を返せば良くて、setterは受け取った変数をメンバー変数に代入してあげるだけです。

 

2.参照についてまたやりました

ちょっと前に参照をやったのですが、また出てきました。

annkate.hatenablog.com

前回学ばなかったことのなかで、参照に他の変数を代入しても参照先は変わらないということがありました。

ポインターだったら、

int value = 40,other = 0;

int* pointer = &value;

としたとき、pointerに入ってるのはvalueのアドレスですが、

pointer = &other;

とした場合はpointerにはotherのアドレスが代入されます。

 

ただ、

int& referernce = value

としたときは

reference = other

としてもアドレスは変化せずotherが持つ値がreferenceひいてはvalueに代入されるだけで参照が指し示すアドレスには変化がないのです。

 

あとconst参照についてももう少し踏み込んでやりました。

前回は「とりあえず使った方がいい」というふわっとした感じの説明に留めましたが色々理由があるようです。

まず、参照は同じアドレスを参照先と持つのでその値を変更できるという特徴を持ちます。

 

ですが、const指定されているにも関わらず変更できるとかなったら大変なので、この場合参照にもconst指定を行います。

通常の変数をconst参照することもできます。

 

const参照は主として関数の引数としてクラスや構造体を受け取る場合などで良く使われます。

例:変数の値を読み込みたいけど書き込む必要がないとき

 

ただ、このconst参照は一回付けたら外すことはできません。たとえ参照元がconstされていなくても、です。

 

3.型推論についてやりました

変数の宣言時に初期値を与えているときに、変数の型と初期値の型が同じになるように宣言して!とコンパイラにお願いすることを型推論というらしい。

auto 変数名 = 初期値;

この時初期値がない場合はコンパイルエラーとなる。

 

例えば auto d = 3.14の時はdはdouble型に推論される―みたいな。

この初期値は別に裸の形じゃなくても、関数でreturnされる値とかでもOK。

 

でも、範囲for文で走査するときに得られる各要素の型にautoと書くと、要素の型を推論したうえでループすることができる。

 

 int array = { 0,1,2,3,4 };
for (auto e : array)

{

std::cout << e << std::endl;

}

便利だね。

 

その他、任意の式の型を調べる構文もある。

・初期値を持たない変数の宣言

・テンプレート(後述らしい)

などで使われる。

 

decltype(式);

 

こうすると、式の中で展開されたものの型を返す。

だから、

int i = 1;

decltype(i) j;

とかするとjはint型になったりする。

 

あとは関数の前に

decltype(1) one ()

{

return 1;}

みたいな感じで使ってたけど、よくわからない。難しい。

ただ、()の中に1が入ってるからこれはintってことなのかな。だとしても謎だけどね。

 

ちなみに配列の型推論はできないのでやらない方が良い。怒られる。

 

4.型の別名定義について学びました。

ここら辺知らないことばっかだね。

型ってのはintとかfloatとか。色々な名前があるけれども、プログラムを見やすくしたりするために型に別名を与えることがある。

この時に使うのがusing宣言。typedefじゃないんだね。usingはテンプレートなどでめちゃくちゃ活用できるのがうまみらしいね。C++ではテンプレートが偉大なのか。

 

using 新しい型名 = 古い型名;

 

もちろんusing宣言で型に別名を与えたとしても、元の名前を使うことは可能。

 

ちなみにtypedefの宣言方法は

 

typedef 古い型名 新しい型名;

だからね!忘れてないだろうね

 

ただ、ここで行ってるのは「元々ある型に別名をつけている」だけであり、「新しい型を作っているわけではない」ということに注意。

だから、別名を使って関数をオーバーロードすることはできない。

 

ちなみに構造体やクラスは、メンバー関数・メンバー変数以外にもネストした型名を持つことができる。クラスのなかで使うのならそのまま使えるけど、外でそれを使う時は(::)が必要。

 

class CHINCO

{

public:

using integer = int;

void set_value(integer new_value)

};

 

void CHINCO::set_value(integer new_value)

{

integer tmp = new_value;

value = tmp;

}

いやいや!外なのにCHINCO::integerってしてないやん!てなるけども、メンバー関数内はクラスの内側っていう扱いなので、::は使わなくてもOK

 

5.コンソールからの入力方法について学びました

どうせならラムダ式までやってしまおう!

scanf()ってのがCにあったと思うけど、それっぽいのがC++にもある!

それがstd::cin!

 

int i;

std::cin >> i;

 

今までは<<向きだったけど、今回は逆向きになるよ!

 

ちなみに最初にユーザーに入力を促すメッセージを出してるけど、これをプロンプトという。

 

文字列の入力方法はちょっと前にやったstd::string型を使う。

これはcharとかと違って最初に使う容量を決めなくても良いから最高なやつだったね。

ただ、この場合だと空白を含んだ文字列が入力された時に対応できない。

入力された文字列を一行丸々受け取りたい時はstd::getline()を使用する。

 

std::istream& getline(std::istream& input, std::string& str);

 

第一引数にはstd::cinを、第二引数には入力を受け取りたいstd::string型の変数を渡す。

std::istreamはもうわからなすぎるので後で説明するっぽい。とりあえずstd::cinを渡せる型ということで。

 

std::string s;

std::getline(std::cin,s);

 

みたいな感じになるかもね

 

6.本当は怖いラムダ式を学びました

ラムダ式とは関数を必要に応じてその場で定義する構文です。←?

述語を必要とするアルゴリズムやコールバック関数を登録する場合に強力な機能らしい。

[](パラメータ) -> 返す型

{

ラムダ式}

 

みたいな感じで書く。難しい。

 

 

2020/11/04

開きの時間が長いですね。

何もしてないってわけじゃないんだぞ!(何もしてない)

 

1.範囲for文について知り、拡張for文に思いを馳せました。

for文を使って配列を順番に処理していくやり方っていうのは、走査(scan)というらしい。なるほど。

これをやりやすくするツールとして範囲for文というのがあるらしい。

 

for(初期化文 : 範囲(大抵配列名))

{

}

 

 

例えば

for(int i = 0 : range)

{

処理…

}

 

みたいに書くんだけども、この時繰り返しの指定がない。

でも、コンパイラは配列の長さを知ってるので、その長さを勝手に使って走査してくれる。

この時繰り返し毎にiにrangeが代入されていく。実際はiを使ってあーだこーだする。

ただ、インデックス変数を直接操作することは出来ないため、今扱っているのが何番目の要素か、とかはわからない。ホントに順々にしか使えない。

 

2.構造体の初期化について復習しました

typedefとかあったけどそれは前のページを見てね

 

struct product

{

int id;

int price;

int stock

}

 

となっている場合main()で

 

product pen =

{

0,

100,

200,

};

 

と初期化できることは知らなかった。数字だけ書けばいいなんてらくちん!

でも、一応コメントとかで書いてあげるのがマナーなのかもしれない。

 

3.共用体(union)がまた出てきました

共用体は構造体と同じようにメンバー変数を持っている←わかる

それらが全て同一のアドレス上に存在している←わかる

 

どちらにせよ構成されているメンバー変数全てが同じ値を示すことになるので、初期化時には先頭のメンバー変数のみ初期化することになる。

 

このunionは使う機会はないかもしれないらしいが、特別なハードウェア用のプログラムを書く場合に必要になるらしい。なんだそれ!

 

4.列挙体について少しやりました

列挙体は「列挙体が取り得る値を列挙しておき、そのうちのいずれかの値を持っている」変数を作るための型。

 

…??

 

つまり、「1の時は商品A、2の時は商品B」ってやるのもいいけど、そうやるとあとでその値が何を示しているのか分からなくなるのでこの列挙体を使うらしい。

 

基本は

enum class 名前

{

};

 

使う時は列挙体名と列挙値をスコープ解決演算子(::)でつなぐ。そんな名前だったんだね。

 

難しいのでコードを書いておきます。

 

#include <iostream>

 

enum class Category

{

Value1,//先頭は明示的に指定しない限り暗黙的に0になる。

Value2,//値を省略した場合は1つ上の整数の次(これは1)

Value3 = 100,//1つ上の次の整数だと困る場合に明示的に指定できる。

Value4,//また省略した場合は1つ上の整数の次(これは101)

};

 

int main()

{

//列挙体の変数を宣言してValue3で初期化

Category cat = Category::Value3;

 

//列挙体の値に対応した変数を得る

std::cout << static_cast<int>(cat) << std::endl;

}

この時の実行結果は100になる。

 

この時、列挙体変数は整数値を持っているが、整数値に暗黙変換はされないので、int型にキャストしている。不親切だな!

 

また、列挙体変数が何バイト使うのかについてはコンパイラなどの環境によって変わってくるので、「何バイト使うか決めときたいよ!」という場合には列挙体で扱える整数の範囲を指定する方法がある。

 

enum class 名前 : ベースとなる整数型(charだと1バイト…とか)

{

}

 

今回説明したenum classはCでやったenumの拡張版で、C++でもenum自体は使える。使い方は一緒。

ただ、enumでは暗黙変換がされてしまい、それが普通の変数なのか列挙体が入ってる変数なのかが分からないのでよほどのことがない限りはこのenum classを使って変数を得る時にキャストする形にしておいた方が無難かもね。

 

 

2020/10/31

1.コンプレッサーの使い方について今更理解しました。

 

www.ototeku.com

 

www.ototeku.com

素晴らしい記事でした。また思い出しつつ見てみます。

 

2.EQの使い方についてちょっと分かりました

どういう時にかける?

→周波数毎の音質調整

EQは各々の周波数毎の値をいじるだけなので、なってない音を鳴らすことは出来ない。

 

どこにかける?

良くあるのがQを絞って嫌な所をちょっと下げるやり方→具体的には???

ピークをちょっと上げたり下げたりすると音色が効果的に変わる

→これはQ3のアナライザーがめちゃくちゃ役に立つ

 

www.youtube.com

イコライザーをかける目的を持つ

例:低域がうるせえなとか 高域をもうちょっと出したいな

→それをする前にまず各トラックの音量調整を行う!

 

そして、欲しい所をブーストするというよりは欲しい所を出すために他の邪魔な所を消してあげるという考え方で行く方が楽。

 

そして、ピークが出ている部分がサウンドにどのように影響を及ぼしているかを見て、それがうるさかったら下げて欲しかったら上げるのが良いよ。

 

3.ドラムのEQについて少し理解しました

各音色が同帯域にかぶってしまっていることを「マスキング」という。

かぶっている場合どういう処理をするのかを知ることができた。

 

キック

→ローカットを行う 大体処理をしているか分からない程度にかける。

 

かぶっている場合は、どちらを優先したいのかを意識してEQをかける。

もちろん優先しない方にEQをかける。

 

かぶっている部分をアナライザーで見てみて、そこを🎧マークを押しながら削っていく。

 

スネア

→ローカットを行ってピークをそれぞれ見ながら上げたり下げたりする。

 

2020/10/30

1.コンストラクタの役割について知りました

C++においてもコンストラクタはあって、クラスの名前と同じ関数をヘッダー内に規定しておく。

そのクラスのインスタンス(オブジェクト)が作成されるときに生成される。

役割はメンバ変数の初期化など。

返り値は何も書かない(voidもダメ)が、引数は別にOK

 

2.オーバーロードについて懐かしく思いました

Javaでやったオーバーロード(関数の引数の数や中身が違ったら宣言時に適切な関数が呼ばれるもの)がC++にもあると知って懐かしく思いました。

ただ、返り値だけが違う場合はコンパイルできません。

 

3.デストラクタについて知りました

デストラクタはインスタンスが削除されるときに自動的に呼び出される関数。

宣言方法は「~クラス名()」

返り値・引数・オーバーロードなし

 

クラス内でnewしたオブジェクト等をdeleteするときに使う。

 

4.クラスのcppの書き方を学びました

まずプロトタイプ宣言をしたヘッダーファイルをincludeして、

 

Hoge::Hoge() : n1(0) , n2(0)

{

}

 

Hoge::Hoge(int i , int j) : n1(i) , n2(j)

{

}

 

Hoge::~Hoge()

{

}

...

みたいな感じで書く。

 

クラス名::関数名

 

その後にくっついている n1(0) , n2(0)とかはメンバイニシャライザと呼ばれるもので、メンバ変数をここで()の中の数字で初期化している。(この場合はヘッダーファイルにn1,n2というint型変数がある)

こっちの方が{}の中で書くよりも効率が良く、{}の中に書いた場合でもメンバイニシャライザが書いてあればそちらが優先される。

また、constや参照のメンバを生成時に初期化するのにも必要。

 

ちなみに空っぽのコンストラクタ・デストラクタは省略可能。

 

宣言方法は

クラス名 宣言名;

クラス名* 宣言名 = new クラス名(なんか);