Closed39

cpp-module

bayamasabayamasa

C++におけるインスタンス作成する時のコンストラクタの挙動は、以下のようになる。

1.オブジェクトをインスタンス化する。
2.クラスが持つメンバ変数のコンストラクタが起動し、中に書かれている処理が実行される。
3.コンストラクタの内容が実行される。

C++において組み込み型、いわゆるintとかstringなど既に定義済みの型においてはそれぞれコンストラクタが存在する。
C++のコンストラクタの挙動において2がそれにあたり、コンストラクタの内容、つまりコンストラクタ関数の中身が実行される前に、メンバ変数のコンストラクタが起動する。

なのでメンバ変数を初期化したいときに、メンバ変数のイニシャライザを使わずにコンストラクタの処理として各メンバ変数に代入を行うと、2で0初期化し3で代入をするという、余計なことをしていることになるので、なるべくメンバイニシャライザを用いてメンバ変数の初期化を行った方がよい

bayamasabayamasa

配列のオブジェクトをデストラクトする方法
delete []変数名

bayamasabayamasa

参照
C++における新しい参照演算子&の使い方。
関数などに渡すことでオブジェクトの実態そのものを渡す事ができる。
つまりポインタと同じような使い方をすることができる。

ただし、ポインタは値のアドレスを指すのに対し、参照は値そのものを指す。
そのためあるクラスの関数を別の関数で使用するときに、ポインタで渡すのであれば、アロー演算子で操作するのに対し、参照渡しではピリオド、つまりローカル変数と同じ使い方のような対応をする。

bayamasabayamasa

参考
https://programming.pc-note.net/cpp/reference.html#:~:text=参照は何かしらのオブジェクト,こと)%E3%82%92%E6%8C%87%E3%81%99%E3%82%82%E3%81%AE%E3%81%A7%E3%81%99%E3%80%82&text=%E5%A4%89%E6%95%B0%E5%90%8D%E3%81%AE%E9%A0%AD%E3%81%AB,%E3%81%84%E3%82%8B%E5%A4%89%E6%95%B0%E3%81%8C%E5%8F%82%E7%85%A7%E3%81%A7%E3%81%99%E3%80%82&text=%26%E8%A8%98%E5%8F%B7%E3%81%AF%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E3%81%AE%E9%A0%85,%E5%88%9D%E6%9C%9F%E5%8C%96)%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82

bayamasabayamasa
bayamasabayamasa

代入演算子との違い
コピーコンストラクタは初期化時に呼ばれる。
呼び方はA a = A(b); or A a = b;のどちらでも良い。つまり初期化的なものでも代入的なものでもどちらでもコピーコンストラクタが呼ばれる。初期化の場合は。

しかし、一度初期化した値に対して、代入をすると代入演算子オーバーロードが呼ばれる。
http://yohshiy.blog.fc2.com/blog-entry-303.html

bayamasabayamasa

実は派生クラスではoverrideやvirtualを記述しなくてもオーバーライドは可能です。
しかしこれらのキーワードがないと、シグネチャ(引数などの定義)が異なる場合にオーバーライドにならず、新しい関数を定義したことになってしまいます。
これらのキーワードを付けていれば記述ミスなどがあればキチンとエラーになってくれますから、バグの混入を防ぐことができます。

https://programming.pc-note.net/cpp/virtual.html

bayamasabayamasa

override修飾子はc11かららしい...
./ScavTrap.hpp:15:41: error: 'override' keyword is a C++11 extension [-Werror,-Wc++11-extensions]

bayamasabayamasa

pedanticオプション

厳密なANSI CおよびISO C++により要求される警告をすべて出力します.禁止されている拡張機能を使うプログラムをすべて拒絶します.正当なANSI CプログラムおよびISO C++プログラムであれば,このオプションの指定の有無にかかわらず正しくコンパイルされるはずです.しかし,このオプションが指定されないと,特定のGNU拡張機能もまたサポートされることになります.

bayamasabayamasa

継承修飾子

cppにおいて class Hogehoge : 継承修飾子 Fugafugaとしたときに、継承修飾子によって継承されたメンバ関数、メンバ変数の使い方が変わってくる。

  • public・・・基底クラスで設定したアクセス修飾子の設定をそのまま引き継ぐ
  • protected・・・基底クラスでpublicだったものを、protectedにして引き継ぐ。他はそのまま。
  • private・・・基底クラスのメンバを全てprivateで引き継ぐ。
bayamasabayamasa

wshadowオプション
別の名前空間で同じ変数名の変数を初期化したときにコンパイルエラーとするフラグ。
同名変数初期化はコーダーが意図しない初期化などがされるケースがあり、避けるべきである
ex)

	int a = 5;
	{
		int a = 2;
		std::cout << "a: " << a << std::endl;
	}
	std::cout << "a: " << a << std::endl;
bayamasabayamasa

コピーコンストラクタが実行される条件

  1. インスタンスに代入したとき
Dog a;
Dog b = a;
  1. 関数に値渡しをしたとき
#include <iostream>

class Cat
{
private:
public:
	Cat(){}
	~Cat(){}
	Cat(const Cat &other)
	{
		std::cout << "cp kita" << std::endl;
	}
	Cat &operator=(const Cat &other);
	void makeSound(Cat hi){
		std::cout << "meow" << std::endl;
	}
};

int main() {
	Cat a;
	a.makeSound(a);
}
cp kita
meow
  1. インスタンス作成の引数に指定したとき
#include <iostream>

class Cat
{
private:
public:
	Cat(){}
	~Cat(){}
	Cat(const Cat &other)
	{
		std::cout << "cp kita" << std::endl;
	}
	Cat &operator=(const Cat &other);
	void makeSound(Cat hi){
		std::cout << "meow" << std::endl;
	}
};

int main() {
	Cat a;
	Cat b(a);
}

  1. 戻り値にインスタンスを指定したとき
#include <iostream>

class Cat
{
private:
public:
	Cat(){}
	~Cat(){}
	Cat(const Cat &other)
	{
		std::cout << "cp kita" << std::endl;
	}
	Cat &operator=(const Cat &other);
	Cat getCat(Cat *hi){
		return *hi;
	}
};

int main() {
	Cat a;
	a.getCat(&a);
}
cp kita
bayamasabayamasa

逆にコピーコンストラクタが呼ばれずに、Assigned Operatorのみがよばれているケース

	Cat a;
	Cat b;
	b = a;

ポイントは**コンストラクタは一回しかよばれないという点。
デフォルトのコンストラクタが呼ばれた場合は、コピーコンストラクタはもうよばれない。

bayamasabayamasa

inf, -inf, NaN

少数を表現するfloat, doubleにおけるオーバーフローはinf, -infで表現する
NaNは0で割ったりするときの、値ではない(Not a number)を表現する

bayamasabayamasa

キャスト
static_cast: 基本的なキャスト
dynamic_cast: 派生元→派生先にキャストするときに使用する
const_cast: const, volatileを外したいときに使用する
reinterpreter_cast: ポインタ型を他のポインタに変換する。数値をポインタ型にしたいときも有効

reinterpreter_castは型安全かどうかを考慮しないので、最も非安全である。使用しなくていいのであれば他のキャストを使うべきである

bayamasabayamasa

getterのconst参照渡しはやめたほうが良いらしい
以下の文章を見る感じconstには穴があって工夫とconstの定義の仕方によっては穴をつくようなプログラミングができる。
そのためprivate変数の中身が書き換わってしまう場合が存在する。

http://sackys-blog-extend.cocolog-nifty.com/blog/2012/10/post-7f95.html
https://qiita.com/pink_bangbi/items/a36617bf1d5923743d69

本当にメモリの容量が少ないハードのときに改めて考えるべきである。

bayamasabayamasa

上記の方法では、値が全て同じ場合でないと初期化できない。
「std::vector<型> オブジェクト名(型* first, 型* last);」と記述すると、first から last が指す先までのデータで動的配列を初期化する。 厳密に言うと、last は最後の元データの次を指す。[first, last) の範囲を元に、動的配列を初期化する。
通常配列でデータを指定し、それを元に動的配列を構築し初期化出来る。

http://vivi.dyndns.org/tech/cpp/vector.html

bayamasabayamasa
bayamasabayamasa

resizeはvector.size()の戻り値を変更する。その際に値が入っていない場所は初期値埋めをする。
reserveはvector.capacity()の戻り値を変更する。初期値埋めはしない。
vectorは初期化のときに要素数を指定することにより動的メモリを予め確保することができる。
しかし要素数を指定していないvectorに対してもpush_backなどで要素を追加するときに、動的メモリを確保することができる。

つまりreserveや要素数の指定はあくまで処理速度の優先度を変えただけ。

bayamasabayamasa

getterを参照にする場合、swapなどの関数を外部から呼び出したとき、private変数の値が書き換わってしまう。その場合private変数が外部から変更を加えられてしまうのはまずいので、constなどをprivate変数に入れる必要がある。
逆にそうすると今度はsetterで値が入れられなくなる。(constは再代入できない)
以下のようなconstructorの呼び出しのときに設定できるようになる
http://www7b.biglobe.ne.jp/~robe/cpphtml/html02/cpp02022.html

c++におけるgetterのベストプラクティスは何なのだろうか

bayamasabayamasa

getterで扱うときに通常→constに変換してあげる
const std::string &GetData() const;

このスクラップは2023/04/09にクローズされました