ジャンル雑多なゲーム・ゲーム制作関連の色々な情報を取り扱っているブログ。最近はBlenderについてが中心。
[C, C++学習]C, C++言語再学習ノート-10日目- –C++とは、クラスを小出しにオブジェクト指向について、ヘッダ、名前空間、ストリーム演算子、cout、endl、cin、stringクラス

[C, C++学習]C, C++言語再学習ノート-10日目- –C++とは、クラスを小出しにオブジェクト指向について、ヘッダ、名前空間、ストリーム演算子、cout、endl、cin、stringクラス

そもそもC++とは、クラスを少し先駆けてネタバレしつつオブジェクト指向について、ヘッダをCと比較、名前空間、再び出てきたストリームとストリーム演算子、実はオブジェクトcoutとendl、cin、stirngクラス 勉強しなおしの記録というか学習ノート-10日目-

Unreal Engin4すごい!(語彙力)ってなったので、少しいじりつつ、むかーしかじった事あるC,C++の学びなおしの学習ノート。この連載記事の詳しい趣旨と注意事項は1日目をご覧ください。

C++編はっじまーるよー!

…すみませんやっとC++入れるのでテンションが上がってキャラが崩れております。
(え?普段から?それなら平常運転で安心ですね!)

目次

C++とは –基本的なところをつらつらと

C++』。名前からしてCと関係ありそうな感じありますよね?というか、コンパイルの環境が、既にC++用の環境だったりして、Cやってれば何かとその名前を見聞きするはずです。

薄々、「上位互換とか、後継的な言語なのかな?」という、印象をお持ちだと思います。

実は全くその通り。

C言語は、1972年に登場してからしばらくは、機械屋さん界隈では主流として使われる言語でした。ですが、時代は次第にコンピュータ性能の進化によって、複数人でチームを組んでの開発に移行していったのです。

Cの「大規模な開発には向かない」という性質により、徐々に機械屋さん界隈では時代にそぐわないものとなっていきました。

そこで、1983年、大規模開発もできるようにCを継承し、拡張された上位互換の『C++』が登場しました。

最近(というほど最近でもないのか?)、色々な言語が『オブジェクト指向』または、その方向にも対応できるように、拡張されてたりしますよね。『オブジェクト指向』は、現在、プログラミング界隈での主流となる考え方となっています。

C++』は、その『オブジェクト指向』を一番に世に広めた存在と言って過言ではない存在なのです。

オブジェクト指向とは –概念でしかないものを現実世界の物質に落とし込んだ考え方

オブジェクト指向(object-oriented)という言葉自体は、1972年から80年にかけてプログラミング言語「Smalltalk」を公開した計算機科学者アラン・ケイが、その言語設計を説明する中で初めて生み出されている[1]。そこから遡って1967年に公開されていた「Simula 67」のクラスオブジェクトの設計もオブジェクト指向の発端と見なされるようになった[2]。データとコードの複合体であるオブジェクト(object)という用語を確立したのはSimula 67であったが[3]、その設計は手続き型プログラミングの機能拡張に近いものである。アラン・ケイ自身は「LISP」の影響を受けた事を強調しており[1]、実際にクラスの仕組みを除いたSmalltalkのオブジェクト指向設計は完全に別物であった。1958年に公開されていたLISPMIT人工知能(AI)研究と深い関わりを持っていた。その後、計算機科学者ビャーネ・ストロヴストルップが1983年に公開した「C++」が契機となって、オブジェクト指向に関連する様々な考え方が再定義されている。C++の設計はSimula 67の方をモデルにしていた。
上述の様にオブジェクト指向とは元々プログラミング・パラダイムとして編み出された理論であったが、1980年代からデータベースOSの開発にもその設計構想が活かされるようになり、1990年代になるとソフトウェア工学の幅広い面にも応用されて、オブジェクト指向を土台にした様々な分野が開拓される事になった。

引用元:オブジェクト指向 – Wikipedia

本来、コンピュータ上の演算であって、プログラム自体や変数は、形を持たない無象のものなわけです。以前の記事でご紹介したCでの構造体みたいな変数の集合体みたいなものもありますが、やっぱり数値のまとまりなわけで、今一つイメージが掴みにくい。

C++では、C++最大の特徴と言える『クラス』というものを使って、オブジェクト指向的に、その概念を管理できます。ちなみに、この『クラス』は、構造体を拡張したものでもあります。

クラスとは –オブジェクト指向の根幹を担うもの

『クラス』とは、オブジェクト(物)として、変数や関数などを管理するためのものです。

例として”自動車”というオブジェクトを作ってみます。

まずは、自動車の状態を表すのに値が必要ですね。なので、いくつかの変数をクラスに紐づけます。

int gasoline = 10; // ガソリン
double power = 0.5; // パワー
double speed = 0.0;// 現在の速度 
double distance = 0.0;// 移動距離 

この変数なのですが、クラスではクラスを構成するもの1つ1つを“メンバ”と言い、変数であるものは”メンバ変数“と言います。構造体でも変数のことを”メンバ”と言いましたが、クラスでもそう呼びます。

ですが、『メンバ”変数”』とついたところから、予想がついている方もいらっしゃるかと思います。クラスは、変数以外にも含めることが出来るんです。

Cで扱った構造体と違い、関数も含めることが出来ます。(※実はC++での構造体は、関数も含められます)

そして、この関数を“メンバ関数”または、“メソッド”と呼びます。

このメソッドを使って、オブジェクトの動きを制御・管理する訳です。 今パッと思いついたものを書いただけの単純なものですが例えば、自動車であれば、

void move(){
  gasoline--;//ガソリンの量を減らして、
  if(gasoline < 0){//ガソリンが0未満でなければ
    speed += power; //現在の速度にパワー分足して、
    distance += speed;  //その現在の速度を移動距離に足す
  }
}

みたいな感じのメソッドを持つことになります。他にも、停止する際の処理、ガソリンを補給する際の処理など、色々追加できそうですが、とりあえず説明用にこれだけにしておきます。

そして、これをクラスとして宣言して定義したら、それを“インスタンス”と言うクラスからの生成物をいくらでも量産することが出来ます。クラスはただのテンプレートで、実際に使うのはそれ自体ではなく、それのコピーのインスタンスなのです。

イメージとしては、金型で鋳造物一杯生成する感じ。

もちろんこれを基にカスタマイズ(継承)を加えることも出来たりするのですが、この話はクラスの話を含めて機会を改めて詳しくやります。

C++で文字を出力する際のCとの違い

C++でもC言語がそのまま記述できてしまったりするのですが、とりあえずC++の一般的なやり方で「Hello, World!」を表示してみます。拡張子は「.c」ではなく、「.cpp」です。ご注意ください。

#include <iostream>

using namespace std;

int main() {
	cout << "Hello, World!" << endl;
	return 0;
}
「"#include"はわかる。けど、この<iostream>ってなに?<>に入れるのってヘッダファイルじゃないの?なんで".h"ついてないの?」
「"using namespace std;"ってなに?」
「あれ?printf()どこ行った?"cout"と"endl"ってこれなに?」
「ていうか、なんで"<<"シフト演算子使ってるの?」

様々疑問は湧かれるかと思いますが、一つ一つ順番に説明しますね。

ヘッダ –Cと違って”.h”が付きません

<iostream>というヘッダは、入出力ライブラリの一部です。”cout”などが宣言されています。

“#include”で読み込んでいたヘッダファイルなのですが、C++のヘッダの場合、”.h”が付かないのが普通です。ちなみに、”.h”をつけるものもインクルードできますが、“.h”があるのとないのとでは、それは全くの別物なのでご注意ください。

明確な違いは、”.h”のあるなし以外にも、Cではヘッダファイルをインクルードすることによって、そのヘッダファイルによって宣言されている”関数”が使えるようになりましたが、C++では、”クラス”が使えるようになるという点があります。

名前空間(namespace) –Cにはない、C++での重要な概念の1つです

『C++』は、複数人のチームで行う大規模開発向けにCから拡張され、発表された言語だと先ほどもご説明しました。そして、そういう複数人で行う開発の場合、変数や関数名、あるいはクラス名などが被ってしまう危険性が、個人での開発と比べ段違いに上がる訳です。

そう言った場合、深刻なトラブルに発展しかねないため、この『名前空間』というものが大変重要な役割を果たします。

まず、説明のために、先ほどの 「Hello, World!」と表示するためのソースコードを、この名前空間(namespace)を使わずに書き直してみます。

#include <iostream>

int main() {
	std::cout << "Hello, World!" << std::endl;
	return 0;
}

先ほどは、”using namespace std;”という記述が、main()関数の前に合ったわけですが、それを消して、代わりに、”cout”と”endl;”の前に”std::”というものが出現しました。

つまり、”std”という名前空間内で記述された、”cout”と”endl”を呼び出しているわけです。

先ほどの、「”using namespace ~”」という記述をすると、その「”~”部分の名前空間名を省略する」、という意味になり、上で記述したように、”std”を省略することができる訳です。

そして、これが大規模開発のために重要なのですが、同じ名前のものでも、 それが管理されている”名前空間”が違うものは、別物として扱われるため、”競合”を避けることができる訳です。

cout, endl, << –関数ではなくオブジェクトだったり、ストリーム演算子だったりします

まず”<<“は、『ストリーム演算子』と言って、『ストリーム』に「出力(“<<“)」したり、「入力(“>>”)」したりということをこれで指示する訳です。ちなみに、シフト演算子としても使えるようです。

ストリームやシフト演算子は過去記事で解説しましたので、もしわからない方はよろしければ参考にどうぞ。

そして、”cout”は関数ではなく、標準出力をつかさどるオブジェクトで、過去記事でCの標準入出力装置の件を取り扱った時にちらっと話題に出た、”printf()”の出力先の”stdout”(C言語でコマンドプロンプトを指す)みたいなものです。

“endl”の方は、「改行(“\n”)」を意味します。

つまり、

cout << "Hello, World!" << endl;

は、書き直せば、

コマンドプロンプトに、"Hello, World!" を出力した後、改行 を出力して。

という意味になります。

文字を入力するには? –cinオブジェクト

先にソースコードお見せします。

#include <iostream>
#include <string>

using namespace std;

int main() {
        string str;
	int num;
	cout << "何か数値を入力してください:";
	cin >> num;
	cout << "入力された値:" << num << endl << "続いて、何か文字列を入力してください:";
	cin >> str;
	cout << "入力された文字列:" <<str << endl;
	return 0;
}

ちなみに実行結果↓

何か数値を入力してください:24
入力された値:24
続いて、何か文字列を入力してください:あいうえお
入力された文字列:あいうえお

まず、先ほどは”<<“だけであったストリーム演算子が、cinと共に使う際に逆の”>>”が使われていることにお気づきでしょうか?

先ほどもご説明したように、ストリームに流す方向によって、「出力(“<<“)」、「入力(“>>”)」という風に指定するんでした。

ですから、入力の際は、”>>”な訳です。

続いて、”cin”。予想がお付きのことと思いますが、これは「標準入力をつかさどるオブジェクト」で、先ほど出てきた”cout”とは対となるオブジェクトですね。

さて、問題は↓の部分。

#include <string>

と、↓部分。

string str;

“string”というのは、型のように見えますが、実はクラスだったりします。『stringヘッダファイル』をインクルードして使います。

とっても便利に文字列を扱えるクラス –stringクラス

ソースコードと実行結果からお分かりになるかと思われますが、文字列を操作・管理するのに使います。これがまた便利で、これと、ストリーム演算子を用いた入出力のシステムがあるおかげで、CからC++では文字列の扱いが格段に楽になったと思います。

実は、“+”演算子で、文字列と文字列の連結が簡単にできるようになっていたりします。

#include <iostream>
#include <string>

using namespace std;

int main() {
	int num;
	string str, str2 = "入力された文字列:";
	cout << "何か数値を入力してください:";
	cin >> num;
	cout << "入力された値:" << num << endl << "続いて、何か文字列を入力してください:";
	cin >> str;
	cout << str2 + str << endl;
	return 0;
}

実行結果↓

何か数値を入力してください:15
入力された値:15
続いて、何か文字列を入力してください:あいうえお
入力された文字列:あいうえお

他にも文字列を操作できる演算子のパターンをご紹介します。

演算子説明
+= 代入演算。文字列の連結を行えます。 string str = “aiu”, str2 = “eo”;
str += str2;
cout << str << endl; //実行結果:aiueo
== 比較演算(等価)。文字列の比較が行えます。結果が”真”であれば”1″、”偽”であれば”0″。 string str = “もじれつ”, str2 = “もじ”;
cout << ( str == str2 ) << endl; // 実行結果:0
!= 比較演算(非等価)。(先ほどとは逆バージョンの)文字列の比較が行えます。結果が”真”であれば”0″、”偽”であれば”1″。 string str = “もじれつ”, str2 = “もじ”;
cout << ( str != str2 ) << endl; // 実行結果:1
> 比較演算(大なり)。文字列の比較が行えます。左のオペランド(被演算子)が、右のオペランドよりも大きい場合、”真”。等しかった場合や、小さかった場合に”偽”。 string str = “もじれつ”, str2 = “もじ”;
cout << ( str > str2 ) << endl; // 実行結果:1
< 比較演算(小なり)。文字列の比較が行えます。左のオペランド(被演算子)が、右のオペランドよりも小さい場合、”真”。等しかった場合や、大きかった場合に”偽”。 string str = “もじれつ”, str2 = “もじ”;
cout << ( str < str2 ) << endl; // 実行結果:0
>= 比較演算(大なりイコール)。文字列の比較が行えます。左のオペランド(被演算子)が、右のオペランドよりも大きい場合や等しかった場合、”真”。小さかった場合に”偽”。 string str = “もじれつ”, str2 = “もじ”;
cout << ( str >= str2 ) << endl; // 実行結果:1
<= 比較演算(小なりイコール)。文字列の比較が行えます。左のオペランド(被演算子)が、右のオペランドよりも小さい場合や等しかった場合、”真”。大きかった場合に”偽”。 string str = “もじれつ”, str2 = “もじ”;
cout << ( str <= str2 ) << endl; // 実行結果:0

あとがき

やっとC++までこぎつけた!

CとC++を比べた時にこのstringクラスの便利さは、特筆すべきものだと思い、ここまで何とかまとめてみました。

Cは結構覚えてて、割と飲み込みも早かったんです(当社比)けど、C++は実はクラスまではやった気がするんですが、全部やらずにどこかで折れた気がするんですよww……orzだから、どこからかはわかりませんが、普通の、”再”が付かない学習になりますので、ちょっとC++からは、結構ゆっくりじっくり学習が進むと思います。

と思ったんですが、…実はCに『共用体』っていうのあるんですがそれを記事書くの忘れてて、さらに”const”っていうので名前を出しただけで定数に関してはマクロの”#define”しか書いてなかったから、”const”と”enum”と、それに関連して、”列挙型”もすっぽ抜けてるし…orz

でも、これ以上ここで停滞したら腐っちゃう気がするのでモチベーションのためには放置、あるいは番外その2的に書くか、C++で使う時におまけ的に説明するか…って感じですね(^_^;)

学習第一!でもモチベーション大事に!でやっていきます!!!どうか温かい目で見守って下さるとうれしいですm(_ _)m

ご意見・ご感想・ご質問、また誤字脱字や、もっといい方法あるよといったご指摘などございましたら、お手数ですがコメント欄やtwitterアカウントほろほろり(@_horo_horori)へお願いしますm(_ _)m

参考にさせていただいたページ・サイト一覧

Pocket