C++でプログラミングをする場合、C++用の「処理系」(後述)が必要
有名な処理系としては、例えば、Borland C++、Visual C++、gccなどがあります。
※Borlandは開発が終わっています。Embarcaderoが引き継いだbuilderも中身はclangになっています(ただしとても古いやつ)。
覚えるのであればClangがよいみたい(コメントでアドバイスいただきました)
//hello.cpp
#include <iostream>
using namespace std;
int main()
{
cout << "hello" << endl;
}
実行結果は、画面に「hello」と打ち出されるだけです。
「//」ではじまる部分は、行末までがコメント
「#include 」は、「標準的な入出力に関して必要な情報を取って来い」という程度の意味です。この行は基本的にいつも書くことになります。
「using namespace std;」は、「プログラム中でいろいろなものの名前を簡単に書くため」と思っておいてください。(これも基本的にいつも書く)
「int main()」はこれからプログラムの「中心部分(本体)」が始まるという「合図」
「cout << "hello" << endl;」coutは画面を表わし、<<は「そこへ押し込め」などの意味です。endlは「改行」を表わし、「;」は「命令の終わり」を意味します。
string name;
stringは、「文字列」という意味
stringを使うときには、
#include
という行を上のほうに書くことになっています。
「stringを使うために必要な情報を取って来い」という程度の意味
//hello2.cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
cout << "こんにちは。私はコンピュータです。" <<endl;
cout << "あなたの名前を入力してください。" <<endl;
cin >> name;
cout<<name<<"さん。よろしく。"<<endl;
}
nameを定義して、
こんにちは。私はコンピュータです。
あなたの名前を入力してください。
と出力さ、
「cin >> name;」これはユーザの入力を待ち、入力があれば、それをnameに格納するという意味
入力された文字列がnameに格納される
〇〇さん。よろしく。
と画面に出る
int x;
intは整数を表す
業界用語では「変数」といます。
#include <string>
「#include」は、「必要なものを持って来い」(インクルードするといいます)という程度の意味です。そして、<>の中には、入出力に必要な「情報」が入っている。
基本的なものに関しては、何もインクルードしなくてよいことになっています。たとえば、intは、何もインクルードしなくても使える。
重要なものは使っているうちに覚えます
using namespace std;
coutの正式な名前は、std::coutなのです。
cin、endlも同様にstd::cin、std::endlです。
std::endl
苗字と名前みたいなもので、名前が同じものがあれば苗字をつけることもある(大きなプロジェクトの時)
最初のうちは苗字と名前を書くのはめんどくさいので、名前だけ書けるようにしている。(省略できる)
名前が被るようになったら苗字もつけないといけない。
※難しく考えないための例えです。
省略なしバージョン下
//「using namespace std;」はない
#include <iostream>
int main()
{
std::cout << "hello" << std::endl;
}
C++はオブジェクト指向に都合がよい言語です。
オブジェクト指向型プログラムとは、クラス、継承、仮想関数を使ったプログラムのこと。
一般的な言い方では、「オブジェクト指向は、クラス、継承、ポリモーフィズム」
string name;
業界用語では、「定義する」と言います
変数の一般的な定義の仕方は、
型 変数;
stringが型で、nameが変数になる。
class Neko
{
private:
string name;
public:
Neko(string s){
name = s;
}
void naku(){
cout<<"にゃあ。俺様は"<<name<<"だ。"<<endl;
}
};
class クラス名
{
中身
};
などと定義するものなのです(「;」を忘れないように注意してください)。
Neko(string s){
name = s;
}
これはコンストラクタという重要なもの
NekoというクラスにあるNekoという名前の関数なのです。このように、クラス名と同名の関数は、特別なものでコンストラクタとよばれるのです。
また「外から受け取るデータ」のことを業界では引数といいます。
クラスNekoを書いたから、次は、そのオブジェクトを生成し、それを使うコードを書く
オブジェクトは、
Neko dora("ボス");
のように生成することができます。
int main()
{
Neko dora("ボス"); //「ボス」というの名前を持ったdoraが生成される
cout<<"あなたの名づけた猫がメモリ上に生成されました。"<<endl;
cout<<"猫が鳴きます。"<<endl;
dora.naku();
}
出力される文字は
あなたの名づけた猫がメモリ上に生成されました。
猫が鳴きます。
にゃあ。俺様はボスだ。
Nekoオブジェクトdoraの生成
ボスが、引数としてNekoのコンストラクタに渡され、そのコンストラクタが実行される
クラス名 変数(引数);
というコードを書くと、「この変数で表わされるオブジェクトが生成され、そのときにコンストラクタが実行される」ということです。
dora.naku();
変数.関数(あれば引数);
というコードを書くと、この変数(=「オブジェクト」を表わす)に対して、関数が実行されるということです。
クラス内にある変数は、メンバ変数とかデータメンバといいます。また、クラス内の関数はメンバ関数といいます。要するに、クラス内のものはメンバを付ける。
コンストラクタ
先ほどのコードで行くと
Neko(string s){
name = s;
}
これを短くする方法もある
Neko(string s) : name(s){}
一般的にはこんな使い方をするみたい
オブジェクトのデータを変えない関数には、constを付ける
nakuは、オブジェクトのデータ(今はnameのことです)を使っているけど、変更はしていないので、constを付けるべき関数ということ
void naku() const{
cout<<"にゃあ。俺様は"<<name<<"だ。"<<endl;
}
クラス定義の1番上のprivate:は省略してもよいことになっています。これがなくても、public:の上にあるものは、プライベート(非公開)になる
以上のことをまとめるとこのようにクラスを書ける
class Neko
{
string name;
public:
Neko(string s) : name(s){}
void naku() const{
cout<<"にゃあ。俺様は"<<name<<"だ。"<<endl;
}
};
ちなみに最初に書いたコードはこちら
class Neko
{
private:
string name;
public:
Neko(string s){
name = s;
}
void naku(){
cout<<"にゃあ。俺様は"<<name<<"だ。"<<endl;
}
};
またクラス外に書く関数をインライン関数という
処理が長い場合、複数使う場合はインライン化するようだ
Nekoでいうと
class Neko
{
string name;
public:
Neko(string s);
void naku() const;
};
Neko::Neko(string s) : name(s){}
void Neko::naku() const{
cout<<"にゃあ。俺様は"<<name<<"だ。"<<endl;
}
こんな感じになる
クラス内には「この宣言があるよ」とだけ書いて、内容はクラス定義の下に書く
復習ですが
「Neko::Neko」は「NekoというクラスのNekoという関数(コンストラクタ)」という意味
この[Neko::]を書かないとどのクラスのメンバ関数か分らなくなる。
最終的なコードはこちら
//neko3.cpp
#include <iostream>
#include <string>
using namespace std;
class Neko
{
string name;
public:
Neko(string s);
void naku() const;
};
Neko::Neko(string s) : name(s){}
void Neko::naku() const{
cout<<"にゃあ。俺様は"<<name<<"だ。"<<endl;
}
int main()
{
string s;
cout<<"猫を生成します。名前を入力してください。"<<endl;
cin>>s;
Neko dora(s); //コンストラクタが実行され、文字列sの名前のdoraが生成される
cout<<"あなたの名づけた猫がメモリ上に生成されました。"<<endl;
cout<<"猫が鳴きます。"<<endl;
dora.naku(); //doraに対してnakuを実行
}
出力は
猫を生成します。名前を入力してください。
○○
あなたの名付けた猫がメモリ上に生成されました。
猫が鳴きます。
にゃあ。俺様は○○だ。
次はロケットを作ろうとなったとき、
クラス ロケット
データメンバ:燃料
現在の速度
メンバ関数 :コンストラクタ
加速
このように設計すると思います。
メンバ変数はprivate、メンバ関数はpublicとします。
class Rocket
{
int nenryo; //燃料
int sokudo; //現在の速度
public:
Rocket(int); //コンストラクタの宣言
void kasoku(); //加速を表す関数の宣言
};
//コンストラクタの定義
//nenryoに引数として与えられる値(xで表す)を入れ、sokudoに0を入れているだけです
Rocket::Rocket(int x) : nenryo(x), sokudo(0){}
//加速を表す関数の定義
void Rocket::kasoku(){
sokudo += 2;
nenryo -= 2;
}
コンストラクタの定義は
燃料がx
速度が0 で初期化をしている。
ちなみに意味は
sokudo = sokudo + 2;
nenryo = nenryo - 2;
こんな感じ。
今の設計だと燃料がなくても加速するので、if文を使って、燃料が無いときの動きを加える
//加速を表す関数の定義
void Rocket::kasoku()
{
if(nenryo >= 2){
sokudo += 2;
nenryo -= 2;
cout<< "現在の燃料は" << nenryo << "です。" << endl;
cout<< "現在の速度は" << sokudo << "です。" << endl;
}
else{
cout << "燃料切れです。加速できません。漂流です。" <<endl;
}
}
燃料が2以上であれば上の方、2より下であればelse文が出力される
出力コード+if文を追加した改良版
//RocketSample.cpp
#include <iostream>
using namespace std;
class Rocket //改良版ロケット
{
int nenryo; //燃料
int sokudo; //現在の速度
public:
Rocket(int x); //コンストラクタ
void kasoku(); //加速を表す関数
};
//コンストラクタの定義
Rocket::Rocket(int x) : nenryo(x), sokudo(0){}
//加速を表す関数の定義
void Rocket::kasoku()
{
if(nenryo >= 2){
sokudo += 2;
nenryo -= 2;
cout<< "現在の燃料は" << nenryo << "です。" << endl;
cout<< "現在の速度は" << sokudo << "です。" << endl;
}
else{
cout << "燃料切れです。加速できません。漂流です。" <<endl;
}
}
int main()
{
cout << "ロケットをメモリ上につくります。燃料(整数)を入力してください。"<<endl;
int n; //ユーザの入力した値を格納する変数をひとつ用意しました。その名はnです。
cin >> n; //ユーザの入力した数字をnに代入しました。
//nをコンストラクタに渡してロケットをつくります。
Rocket ohtori(n); //これでnの値がコンストラクタの定義のxにコピーされ、
//コンストラクタの中身が実行され、nenryoの値がnの値に
//なったロケットohtori(鳳号)が生成されるわけです。
//このohtoriをオブジェクトなどとよぶのでした。
cout<< "加速します。" <<endl;
ohtori.kasoku(); //ohtoriに対してkasokuを使っています
cout<< "また、加速します。" <<endl;
ohtori.kasoku(); //ohtoriに対してkasokuを使っています
cout<< "またまた、加速してみます。" <<endl;
ohtori.kasoku(); //ohtoriに対してkasokuを使っています
cout<< "鳳号の冒険は終わりました。" <<endl;
}
このような形になります。
次は
クラス コップ
データメンバ: 中の水(の量)
メンバ関数 : コンストラクタ
水を出す
コップの中身(量)を決めることができる
class Glass
{
int nakami; //水の量
public:
Glass() : nakami(10){} //引数を取らないコンストラクタ
void dasu(){ nakami -= 2; } //水を出す関数
int main()
{
Glass glass; //glassという名のコップを生成。(以下の解説を参照してください。)
//引数を取らないコンストラクタが呼び出され、中に10の水を入れられる。
cout << "コップglassをつくりました。" << endl;
cout << "glassから水を出します。" << endl;
glass.dasu();
cout<<"終了"<<endl;
}
コップglassを作りました。
glassから水を出します。
終了
int main の
Glass glass;
は、外からデータを受け取っていないということ、用語でいうと「引数を取らないコンストラクタ」
クラス外にコンストラクタを書いて、出力時に水の量がわかるように修正
//Glass2.cpp
#include <iostream>
using namespace std;
class Glass
{
int nakami; //水の量
public:
Glass() : nakami(10){} //引数を取らないコンストラクタ
void dasu(); //水を出す関数(定義は外で書く)
};
void Glass::dasu(){
nakami -= 2;
cout << "水を出しました。" << endl;
cout << "現在のコップの中身は" << nakami << "です。" << endl;
}
int main()
{
Glass glass; //glassという名のコップを生成。
//引数を取らないコンストラクタが呼び出され、nakamiに10が入れられる。
cout<<"コップglassをつくりました。"<<endl;
cout<<"glassから水を3回出します。"<<endl;
glass.dasu();
glass.dasu();
glass.dasu();
cout<<"終了"<<endl;
}
コップglassを作りました。
glassから水を3回出します。
水を出しました。
.
.繰り返し
.
終了
無くなった場合のif文を追加
if(nakami >= 2){
nakami -= 2;
cout<< "水を出しました。" << endl;
cout<< "現在のコップの中身は" << nakami << "です。" <<endl;
}
else{
cout<< "そんなに水がありません。" <<endl;
cout<< "現在コップの中には" << nakami << "入っているだけです。" <<endl;
}
ユーザが貯める水と出す水を決めれるパターンを作りましょう
//Glass3.cpp
#include <iostream>
using namespace std;
class Glass
{
int nakami; //水の量
public:
Glass(int x) : nakami(x){} //引数を取るコンストラクタ
//ユーザかプログラマに渡される値(xで表される)をnakamiに格納
void dasu(int); //水を出す関数
};
void Glass::dasu(int x){
if(nakami >= x){
nakami -= x;
cout<< "水を出しました。" << endl;
cout<< "現在のコップの中身は" << nakami << "です。" <<endl;
}
else{
cout<< "そんなに水がありません。" <<endl;
cout<< "現在コップの中には" << nakami << "入っているだけです。" <<endl;
}
}
int main()
{
int x; //整数の「いれもの」xの定義。下のcinの前ならどこにあってもよいのです。
cout << "コップを生成します。どれだけ水をいれるか入力してください。" << endl;
cin >> x;
Glass glass(x); //引数を取るコンストラクタが呼び出され、
//水がxだけ入ったglassという名のコップが生成される
cout << "さあ、glassから水を出します。いくら出しますか。入力してください。" <<endl;
cin >> x; //上のxを使いまわしている
glass.dasu(x);
cout<<"終了"<<endl;
}
Glass(int x) : nakami(x){}
このつくりがわかっていれば、理解できる。
復習ですが
Glass(int x){
nakami = x;
}
です。
もし「Glass glass;」と「Glass glass(x);」のように「引数を取らないコンストラクタ」と「引数を取るコンストラクタ」の両方を使いたい場合、
「引数の異なる同名のメンバ関数(コンストラクタも含む)」をいくつ書いてもよい
つまり、2つのGlassオブジェクトを、1つは引数を取らないコンストラクタで、1つは引数を取るコンストラクタで生成できる。
//Glass4.cpp
#include <iostream>
using namespace std;
class Glass
{
int nakami; //水の量
public:
//コンストラクタを2つ書く
Glass() : nakami(10){} //引数を取らないコンストラクタ
Glass(int x) : nakami(x){} //引数を取るコンストラクタ
void dasu(int); //水を出す関数
};
void Glass::dasu(int x){
if(nakami - x >= 0){
nakami -= x;
cout<< "水を出しました。" << endl;
cout<< "現在のコップの中身は" << nakami << "です。" <<endl;
}
else{
cout<< "そんなに水がありません。" <<endl;
cout<< "現在コップの中には" << nakami << "入っているだけです。" <<endl;
}
}
int main()
{
int x;
cout << "水量10のコップ(glass)を生成します。" << endl;
Glass glass; //引数を取らないコンストラクタが呼び出される
//水が10だけ入ったglassという名のコップが生成さる
cout << "さあ、glassから水を出します。いくら出しますか。入力してください。" <<endl;
cin >> x; //上のxを使いまわしている
glass.dasu(x);
cout << "水量20のコップ(glass2)を生成します。" << endl;
Glass glass2(20); //引数を取るコンストラクタが呼び出される
//水が20だけ入ったglass2という名のコップが生成される
cout << "さあ、glass2から水を出します。いくら出しますか。入力してください。" <<endl;
cin >> x; //上のxを使いまわしている
glass2.dasu(x);
cout<<"終了"<<endl;
}
水量10のコップを生成します。
いくら出すか入力してください
〇
水を出しました。
現在の中身は〇です。
水量20のコップを生成します。
いくら出しますか。
〇
水を出しました。
現在の中身は〇です。
終了
Glass glass; と Glass glass2(20); 呼び出すときの引数の型や種類によって決まる。
Glass glass; は何も与えられてないので、10が
Glass glass2(20);は与えられたのでその数値を。
といった感じ。
これまでは1つのクラスで書いてきましたが、次は複数のクラスを使って書いていきます(クラスの使い方)
本当だとクラスを分ける時は大規模なプロジェクトの時に使うもので、このような練習では使う規模ではないですが、無理やり使ってみます。
今回はヒーローと大魔王が戦う簡易ゲームを作る
ルール:
・それぞれ1~5の座標に隠れる
・パワーを100持っている
・相手の座標を予測し攻撃する
・もし座標(隠れ場)が当たれば2倍のダメージ。外せばパワーの無駄になる
・パワーは自由に決めれる。
・お互い1回攻撃できる
・パワーがなくなったほうが負け
//Game.cpp
#include <iostream>
#include <cstdlib> //乱数のために必要(説明は次回)
#include <ctime> //乱数のために必要(説明は次回)
using namespace std;
//ヒーローつまり英雄ですね
class Hero
{
int power; //ヒーローのパワー
public:
Hero() : power(100){} //ヒーローのコンストラクタ、ヒーローのパワーをはじめ100とした
void kougeki_suru(int n); //「ヒーローが攻撃する」関数
void kougeki_sareru(int n); //「ヒーローが攻撃される」関数
};
//「ヒーローが攻撃する」関数の定義、nは攻撃に使うパワー
void Hero::kougeki_suru(int n)
{
cout << "悪党め。正義の攻撃を受けてみよ。" << endl;
cout << "どか~ん!!!" << endl;
power -= n; //攻撃したのでパワーを減らします。
//もちろん本当にパワーをどこかにやったのではなく、単に数値を減らすだけでした。
//もしパワーがまだ0以上ならよし、もし、負になったら、使いすぎで負けとした。
//以下のifとelseはそういう意味です。
if(power >= 0){
cout << "現在のパワーは" << power << "だ。" << endl;
}
else{
cout << "しまった!パワーを使いすぎた。" << endl;
cout << "もうおしまいだ!!!がくっ。" << endl;
cout << "ヒーローは倒れました。" << endl;
}
}
//「ヒーローが攻撃される」関数の定義、nは攻撃されて減らされるパワーの量
void Hero::kougeki_sareru(int n)
{
cout << "くそっ。悪党の攻撃も当たることがあるのか。" << endl;
power -= n; //攻撃されてパワーが減る。
//以下の仕組みはkougeki_suru()とほぼ同じ。
if(power >= 0){
cout << "現在のパワーは" << power << "だ。" <<endl;
}
else{
cout << "やられた。がくっ。" << endl;
cout << "ヒーローは倒れました。" << endl;
}
}
//大魔王。実はヒーローとほとんど同じ構造です
class Daimao
{
int power; //大魔王のパワー
public:
Daimao() : power(100){} //大魔王のコンストラクタ、大魔王のはじめのパワーは100とした
void kougeki_suru(int n); //「大魔王が攻撃する」関数
void kougeki_sareru(int n); //「大魔王が攻撃される」関数
};
//「大魔王が攻撃する」関数の定義、nは攻撃に使うパワー
void Daimao::kougeki_suru(int n)
{
cout << "大魔王様の一撃をうけてみよ。" << endl;
cout << "どか~ん。" << endl;
power -= n; //攻撃したのでパワーを減らします。
//もちろん本当にパワーをどこかにやったのではなく、単に数値を減らすだけでした。
//もしパワーがまだ0以上ならよし、もし、負になったら、使いすぎで負けとした。
//しかし、大魔王のパワーは秘密なので書かない。
if(power < 0){
cout << "しまった!!!パワーを使いすぎた。" << endl;
cout << "む、む、む。無念だ。がくっ。" << endl;
cout << "大魔王は倒れました。" << endl;
}
}
//「大魔王が攻撃される」関数の定義。nは攻撃されて減らされるパワーの量
void Daimao::kougeki_sareru(int n)
{
cout<< "くそっ。正義の味方の攻撃も当たることがあるのか。" <<endl;
power -= n; //攻撃されてパワーが減る。
//以下の仕組みはkougeki_suru()とほぼ同じ。大魔王のパワーは秘密なので書かない。
if(power < 0){
cout << "やられた。がくっ。" << endl;
cout << "大魔王は倒れました。" << endl;
}
}
//対決場所のクラス(ヒーローや大魔王が「もの」なら、対決場所も「もの」ですね。)
class Taiketu_basyo
{
Daimao bu; //対決場所にいる大魔王bu!
Hero you; //対決場所にいるヒーローyou!
int bu_no_basho; //大魔王のいる場所(1~5の数値)、これは後で決まる
int you_no_basho; //ヒーローのいる場所(1~5の数値)、これは後でユーザが決める
public:
Taiketu_basyo(); //対決場所のコンストラクタ、定義はクラス宣言の外で
void taiketu(); //「ヒーローと大魔王が対決する」関数
};
//対決場所のコンストラクタの定義
Taiketu_basyo::Taiketu_basyo()
{
srand( (unsigned)time( NULL ) ); //乱数の初期化=「乱数開始のおまじない」(次回に説明します)
bu_no_basho = rand() % 5 + 1; //rand()% 5は0~4の中のでたらめな数(乱数)
//したがってrand() % 5 + 1は1~5のうちのどれか(次回に説明します)、これで大魔王の場所が決まった
cout << "あなたと大魔王ブーとの決戦です。\n" << endl;
cout << "大魔王ブーは座標1~5のどこかに潜んでいます。" << endl;
cout << "あなたもどこかに身を潜めてください。" << endl;
cout << "身を潜める座標(1~5の数値)を入力してください。" << endl;
cin >> you_no_basho; //ヒーローの場所を入力
}
void Taiketu_basyo::taiketu() //「ヒーローと大魔王が対決する」関数の定義
{
int iti, kougeki; //一時的に必要な「位置」と「攻撃量」の変数(いれもの)
cout << "さあ、あなたの攻撃です。" << endl;
cout << "攻撃の位置(1~5の数値)を入力してください。>> ";
cin >> iti; //攻撃する位置をitiに代入
cout << "攻撃に使うパワー(100以下の数値)を入力してください。>> ";
cin >> kougeki; //攻撃に使うパワーをkougekiに代入
cout << endl;
you.kougeki_suru(kougeki); //ヒーローyouの攻撃
//攻撃量はkougekiに代入された値、この値だけヒーローのパワーは減る
if(bu_no_basho == iti){ //もしbu_no_bashoとitiが一致したら(つまり、ねらったところに大魔王がいたら)
bu.kougeki_sareru(kougeki * 2); //攻撃を受けます。このとき大魔王は
//ヒーローが使ったパワーの2倍を消耗します。
//kougeki * 2とはkougekiの2倍という意味です。
}
else{
cout << "あなたの攻撃ははずれたようです。" << endl; //はずれたら、何も起こらない
}
cout << endl;
cout << "大魔王の攻撃です。" << endl;
cout << "(エンターキーを押してください。)" << endl;
cin.sync(); //cinをフラッシュ(次回に説明します)
cin.get(); //1時ストップ(次回に説明します)
iti = rand() % 5 + 1; //大魔王の攻撃の位置は乱数(ここでは1~5までのうちのどれか)で決まる
kougeki = rand() % 100 + 1; //大魔王の攻撃の量も乱数(1~100までのうちのどれか)で決まる
bu.kougeki_suru(kougeki); //大魔王buの攻撃(大魔王のパワーが減る)
if(you_no_basho == iti){ //当たったら
you.kougeki_sareru(kougeki * 2); //攻撃される
}
else{ //はずれたら
cout << "大魔王ブーの攻撃ははずれたようです。" << endl;
}
}
int main()
{
Taiketu_basyo dokoka; //対決場所Dokokaの生成
//ここでコンストラクタが働き、ヒーローと大魔王の位置が決められる。
dokoka.taiketu(); //dokokaの対決
}
こんな感じです。
この中の(unsigned)time( NULL ) );は「srand() % 100」この乱数を使う時コンピュータに自動で選んでもらうため、これがないといつも同じになる(ランダムではなくなる)
cin.sync();
cin.get();
これは簡単に言うと2行で「プログラムの進行を一時ストップし、エンターキー(リターンキー)で進行を再開する」という意味
今回はクラスの使い分けなので、それがわかれば大丈夫
では続きは第2回からやろうと思います!