C++のメモ書き

ホーム   プログラム  

ちょっとしたこと
  話題更新日時   概要
 整数の割り算   2004/03/26 計算を行うときは、型に注意
 変数の初期化   2004/03/27 変数の初期化
 C言語タイプの文字列   2004/03/27 C言語タイプの文字列の扱い
 比較的新しい型   2004/04/08 比較的新しい型
 ヘッダファイル   2004/04/23 ヘッダファイルの2重読み込み防止
 クラスの雛形   2004/04/29 クラスを作るときの定型
 クラス(自動的に生成されるメンバ関数)   2004/04/29 自動的に生成されるメンバ関数
 explicit   2004/04/23 コンストラクタに付けると良い
 コンストラクタ   2004/05/06 コンストラクタの不正な呼び出し

参考文献
変数の初期化

変数の宣言と同時に初期化を行う場合、次のような記述ができます。

// 以下は同じ
int counter(0);
int counter = 0;

// 配列
int c[3] = {10,11,13};
int c[3] = {1};  //この場合、1,0,0となる。
int c[] = {1,2};

// 文字列
char name[] = "name";
char name[50] = "ab"; // 記憶領域が、50確保されるところが違う。


zen
C言語タイプの文字列の扱い

C言語タイプの文字列の扱うには、<cstring>をインクルードします。

#include <cstring>

char name[40];
int l;
char str1[] = "foo";
char str2[] = "peko";

std::strcpy(name,"sam");	// nameに"sam\0"がコピーされる。
std::strncpy(name,"sam",10);	// 上記と同じだが、10を超える文字数はコピーしない。

std::strcat(name,"sam");	// nameに、"sam"を追加する。
std::strncat(name,"sam",10);	// 上記と同じだが、追加する文字列で10を超える部分はコピーしない。

// strncpy strncat は、文字数が領域を超えると、文字列の最後に\0を追加できない可能性があることに注意。
// Cの文字列としては、不適当な文字列ができてしまうことがある。

l = std::strlen(name);		// 文字列の長さ。\0は数えない。

std::strcmp(str1,str2);		// str1がstr2と等しい場合は、0を返す。
				// str1がstr2より小さい場合は、負を返す。
				// str1がstr2より大きい場合は、正を返す。
				// 長さを比較するのではなく、中身を比較することに注意。


zen
比較的新しい型


・ワイド文字

wchar_t wide;
wide = L'Ω';	// Lを付けることで、ワイド文字であることを示す

・ブール型
 true(真)、または、false(偽)の値を持つ

bool flag;
flag = true;

zen
ヘッダファイル

ヘッダファイルの2重読み込み防止には、以下のテクニックを使います。

#ifndef __CALL_BACK_CLASS__		//__CALL_BACK_CLASS__が定義されていないなら
#define __CALL_BACK_CLASS__		//__CALL_BACK_CLASS__を定義する

//ここに、ヘッダの中身を記述する

#endif

Visual C++では、
#pragma once
とするだけで良いようです。
zen
クラスの雛形

 クラスを作成するとき、以下の記述から、必要に応じて、修正していくと良いと思います。

class sample
{
private:
	sample(const sample&){}
	const sample& operator = (const sample&){}
public:
	explicit sample(){}
	virtual ~sample(){}
};

 この記述では、sample(const sample& old_class)と、const sample& operator = (const sample& old_class)は利用できません。デフォルトの動作で使う場合は、この行をコメントとし、定義して使う場合は、publicで定義して使います。
zen
クラス(自動的に生成されるメンバ関数)

自動的に生成されるメンバ関数には、以下のものがあります。これらのメンバを定義しない場合はコメントを残しておくと、定義の必要がないのか、定義し忘れたのかが明確になります。

class::class()
 デフォルトコンストラクタ

class::class(const class& old_class)
 コピーコンストラクタ
 コピー元のオブジェクトのデータメンバを全て新しいオブジェクトにコピーする関数。
 オブジェクトの静的な変数はコピーされますが、動的な変数に関しては、コピーされないことに注意が必要です。動的な変数を持つ場合は、明示的に定義します。自分だけが使うクラスであり、コピーは使わないと決めた場合は、privateとして、定義すると良いでしょう。この場合、誤ってコピーを使った場合には、コンパイルのときにエラーメッセージが出ます。

class::~class()
 デストラクタ

class::operator = (const class& old_class)
 代入演算子
 コピー元のオブジェクトのデータメンバを全て新しいオブジェクトにコピーする関数。
 オブジェクトの静的な変数はコピーされますが、動的な変数に関しては、コピーされないことに注意が必要です。動的な変数を持つ場合は、明示的に定義します。自分だけが使うクラスであり、コピーは使わないと決めた場合は、privateとして、定義すると良いでしょう。この場合、誤ってコピーを使った場合には、コンパイルのときにエラーメッセージが出ます。
zen
explicit

クラスのコンストラクタに、explicitを付けると、次のような使い方ができなくなります。

class int_array{
	explicit int_array(int size);

int_array test(1);	// これは、正しいが、
int_array test = 1;	// これは、無効になる。


 予想外の使い方をしないように、explicitを付けると良いそうです。
zen
コンストラクタの不正な呼び出し

コンストラクタから、コンストラクタを呼び出して、失敗しました。 といっても、継承に関するものではなく、以下のような記述です。

class foo
{
	int* a;
public:
	foo():
		a(NULL)
	{
	}

	foo(int h)
	{
		foo();
	}
}

 メンバ変数aの初期化を両方のコンストラクタに記述するのが面倒に思えたので、デフォルトのコンストラクタを呼び出すように記述しました。これは、コンパイルはうまくいき、うまく動作しました。しかし、あるとき、突然、動かなくなりました。
 考えてみれば、このようにコンストラクタを呼び出したのでは、コンストラクタの初期化という作業を2回行うことになり、概念的に正しくありません。エラーではないけれども間違った記述だったようです。
zen