戦術的撤退を開始します。

主に最近始めたC++によるプログラミングのメモや その日に思った事などを適当に書き連ねて行こうと思いますよ。
vふりーすぺーしんぐ
テンプレートいじり中
記事の書き方模索中
まともにプログラム書けるようになるまでアクセス数なんていらないんだもんね!う、うそじゃないんだから!ミ ミ
誠に勝手ながら一時的に更新を停止させて頂きます。
やはりまだ記事を書くには知識も技能も時期尚早だと思いました。
もっとまともにプログラムらしいプログラムが作れるようになってから更新を再開したいと思います。

「やさしいC++(第2版)」はプログラムを初めて始める初心者にはとてもおススメできる本でした。
コンパイル、画面への出力、変数、式 演算子・・・関数、ポインタ、配列、構造体そしてC++の真骨頂であるクラスと、「初心者に学ばせる順番」がとても洗練されています。
説明や解説もわかりやすく、丁寧で読み手に負担をかけない文章が心地よかったです。
唯一の欠点は部分コードでの間違えや意味を図りかねる差異が気になったことぐらいです。(徹底的にコードを入力して確認していないと気づかない程度の)
プログラミングをこれから始めたいと思っている方は是非「やさしいC++」を選ぶことをおススメします。

くどいけど「これならわかるC++」はひどかったなぁ・・・

それでは、



―――戦術的撤退を開始します。
やさしいC++ Lesson 15 クラスに関する高度なトピック

#include "stdafx.h"
#include <iostream>
#include "conio.h"
using namespace std;

//Carクラスの宣言
class Car{
	int num;
	double gas;
	char* pName;
public:
	Car(char* pN,int n,double g);	//?
	~Car();	//デストラクタの宣言
	Car(const Car& c);	//コピーコンストラクタの宣言
	Car& operator=(const Car& c);	//代入演算子の宣言
	void show();
};
Car::Car(char* pN,int n,double g)
{
	cout << pN << "を作成します。\n";
	pName = new char[strlen(pN)+1];
	strcpy(pName,pN);
	num = n;
	gas = g;
}
Car::~Car()
{
	cout << pName << "を破棄します。\n";
	delete[] pName;
}
Car::Car(const Car& c)
{
	cout << c.pName << "で初期化します。\n";
	pName = new char[strlen(c.pName)+strlen("のコピー1")+1];
	strcpy(pName,c.pName);
	strcat(pName,"のコピー1");
	num = c.num;
	gas = c.gas;
}
Car& Car::operator=(const Car& c)
{
	cout << pName << "に" << c.pName << "を代入します。\n";
	if(this !=&c){	//コピー先のオブジェクト自身による代入を除く
		delete[] pName;	//コピー先のオブジェクトが既に確保しているメモリを解放する
		pName = new char[strlen(c.pName)+strlen("のコピー2")+1];
		strcpy(pName,c.pName);
		strcat(pName,"のコピー2");
		num = c.num;
		gas = c.gas;
	}
	return *this;
}
void Car::show()
{
	cout << "車のナンバーは" << num << "です。\n";
	cout << "ガソリン量は" << gas << "です。\n";
	cout << "名前は" << pName << "です。\n";
}

int main()
{
	Car car1("mycar",1234,25.5);
	car1.show();
	cout << endl;
	Car car2 = car1;
	car2.show();
	cout << endl;
	Car car3(" ",0,0);
	car3 = car2;
	car3.show();

	getch();
	return 0;
}

[実行結果]
yc56-1

[メモ]
◇コピーコンストラクタ(copy constructor)

コピーコンストラクタは、オブジェクトが他のオブジェクトで初期化される場合に呼び出されるコンストラクタ。
Car::Car(const Car& c)
{
	cout << c.pName << "で初期化します。\n";
	pName = new char[strlen(c.pName)+strlen("のコピー1")+1];
	strcpy(pName,c.pName);
	strcat(pName,"のコピー1");
	num = c.num;
	gas = c.gas;
}

◇代入演算子のオーバーロード
Car& Car::operator=(const Car& c)
{
	cout << pName << "に" << c.pName << "を代入します。\n";
	if(this !=&c){	//コピー先のオブジェクト自身による代入を除く
		delete[] pName;	//コピー先のオブジェクトが既に確保しているメモリを解放する
		pName = new char[strlen(c.pName)+strlen("のコピー2")+1];
		strcpy(pName,c.pName);
		strcat(pName,"のコピー2");
		num = c.num;
		gas = c.gas;
	}
	return *this;
}
やさしいC++ Lesson 15 クラスに関する高度なトピック

#include "stdafx.h"
#include <iostream>
#include "conio.h"
using namespace std;

//Carクラスの宣言
class Car{
	int num;
	double gas;
	char* pName;
public:
	Car::Car(char* pN,int n,double g);	//?
	~Car();	//デストラクタの宣言
	void show();
};
Car::Car(char* pN,int n,double g)
{
	cout << pN << "を作成します。\n";
	pName = new char[strlen(pN)+1];
	strcpy(pName,pN);
	num = n;
	gas = g;
}
Car::~Car()
{
	cout << pName << "を破棄します。\n";
	delete[] pName;
}
void Car::show()
{
	cout << "車のナンバーは" << num << "です。\n";
	cout << "ガソリン量は" << gas << "です。\n";
	cout << "名前は" << pName << "です。\n";
}

int main()
{
	Car car1("mycar",1234,25.5);
	car1.show();

	getch();
	return 0;
}

[メモ]
◇デストラクタ(destructor)
デストラクタは、オブジェクトが破棄されるとき自動的に呼び出されるメンバ関数である。引数と戻り値は持たない。
Car::~Car()
{
	cout << pName << "を破棄します。\n";
	delete[] pName;
}
yc55-1

◇?
P.484
//Carクラスの宣言
class Car{
	int num;
	double gas;
	char* pName;
public:
	Car::Car(char* pN,int n,double g);	//?
	~Car();	//デストラクタの宣言
	void show();
};
これは逆にP.482の部分コードではなかったのだが・・・
さらに加筆したP.490のまとめのコードでもCar::はない。 まぁあっても動くんだけどさ。
やさしいC++ Lesson 15 クラスに関する高度なトピック

P.482
//Carクラスの宣言
class Car{
	int num;
	double gas;
	char* pName;
public:
	Car(char* pN,int n,double g);
};
Car::Car(char* pN,int n,double g)
{
	cout << pN << "を作成します。\n";
	pName = new char[strlen(pN)+1];
	strcpy(pName,pN);
	num = 0;
	gas = 0.0;
}

◇引数取ってるのに・・・
Car::Car(char* pN,int n,double g)
	num = 0;
	gas = 0.0;
なんで0入れるのん?
P.484にあるまとめのコードでは
	num = n;
	gas = g;
となっていたので、ここの場面ではあまり重要ではないのでわざと0を代入させたのかもしれませんが、意図がよく分かりません。。
やさしいC++ Lesson 15 クラスに関する高度なトピック

#include "stdafx.h"
#include <iostream>
#include "conio.h"
using namespace std;

//Numberクラスの宣言
class Number{
	int num;
public:
	Number(){num = 0;}
	Number(int n){num=n;}	//変換コンストラクタ
	operator int(){return num;}	//変換関数
	Number operator++();
	Number operator++(int d);
	Number operator--();
	Number operator--(int d);
	void show(){cout << num << endl;}
};
Number Number::operator++()
{
	num++;
	return *this;
}
Number Number::operator++(int d)
{
	Number n = *this;
	num++;
	return n;
}
Number Number::operator--()
{
	num--;
	return *this;
}
Number Number::operator--(int d)
{
	Number n = *this;
	num--;
	return n;
}

int main()
{
	Number n1;
	int i1 = (int)n1;
	cout << i1 <<endl;
	int i2 = n1;
	cout << i2<<endl<<endl;

	int i3=100;
	Number n2(i3);
	n2.show();
	Number n3 = i3;
	n3.show();

	getch();
	return 0;
}

[メモ]
◇変換関数(conversion function)
	operator int(){return num;}	//変換関数
クラスの値を、別の型の値に変換するメンバ関数を変換関数と呼ぶ。
変換関数は戻り値の型を指定しない。戻される値の型は、変換関数の型名であることがあきらかだからである。
変換関数を定義しておけば、キャスト演算子を使って明示的に型変換ができる。
	Number n1;
	int i1 = (int)n1;
	cout << i1 <<endl;
キャスト演算子を明示的に使わなくてもこの変換関数は機能する。
	int i2 = n1;
	cout << i2<<endl<<endl;
yc53-1

◇変換コンストラクタ
	Number(int n){num=n;}	//変換コンストラクタ
別の型の値をクラスの値にするコンストラクタを変換コンストラクタと呼ぶ。
	int i3=100;
	Number n2(i3);
	n2.show();
	Number n3 = i3;
	n3.show();
引数1つのコンストラクタは変換関数の逆の機能をもっている。
yc53-2