読者です 読者をやめる 読者になる 読者になる

すてにゃん氏の技術ぶろぐ

技術っぽいこと書きます

プログラミング初心者でも必ず絶対にわかるC++超入門

この記事は初心者 C++er Advent Calendar 2015の12月24日の記事です。昨日の担当はhmitoさんでした。
www.adventar.org
qiita.com

この記事はプログラミング始めたい・始めたばかりでとりあえずC++っていうのがやりたいけど難しすぎて進まない…って人向けにありえないくらいわかりやすく全てを解説する記事です(大げさ)。(追記:時間が足りなかったのでにゃーんプログラムの説明だけで終わってしまった)。いいクリスマスプレゼントになればなと思います。あ、ちなみにお仕事ではC++は使っていないし、最近特に書いていないのでおかしな点があればいつでも指摘してくださいっ

にゃーん

入門書とかサイトとかみると多くはまずHello, world!っていう文章を表示するプログラムの書き方から教えると思います。なんじゃそりゃ、って感じだと思うので、変わりに「にゃーん」を表示するだけのプログラムから書いてみましょう。というかまずソースコードをみせます。

#include <iostream>

int main()
{
    std::cout << "にゃーん" << std::endl;
    return 0;
}

はい。こちらが「にゃーん」を表示するだけのプログラムのソースコードです。C++です。実行結果が見たいと思うので、今回はオンラインでC++など色々な言語を試すことができるWandboxというサイトを利用します。画面下の黒い画面に「にゃーん」と表示されてれば成功です。
http://melpon.org/wandbox/permlink/rLy6NfSgdkF0Zxo7

どういうことにゃの?

さて、さっきのソースコードだけ出されてもよくわからないと思うので解説するよ!

まずは最初の行ね。

#include <iostream>

この行をそのまま説明すると、「標準ライブラリのiostreamをインクルードする」ということです。が、それを説明するのがだるいという理由で「おまじない」ということで済ませる入門書とかあるらしい。[要出典]

標準ラブライブ?アニメの話??

標準ライブラリね。日本語でおk?うーんそうだね、別の言い方をするならば「C++とセットでついてきた便利機能とかいっぱいつまったやつ」ってイメージかな?新しくスマートフォンを購入した時に最初から電卓とかメモとかのアプリがついてくる感じ?この例えはおかしいかw とにかく便利なやつがあるのでせっかくなので使っちゃお!って感じ。

ちなみに標準ライブラリと他に、自分でもライブラリが作れたりして、標準ライブラリとは識別されます、以下のように <> を使ってるのは標準ライブラリで、

#include <iostream>

"" で囲まれてるのが標準でついてくるものではないライブラリです。

#include "Nyan.hpp"

自分で便利機能とか色々作ったときこのようにして色々なプログラムで使えるようにすると便利かもね!
(余談ですが上の例でもあるように Nyan.hpp は語尾に .hpp というのをつけてますよね。これは絶対に .hpp をつけるべきというわけではありません。C++的には .h とか .hxx とかにしても問題ないはずです。ただ、標準ライブラリには何もついていないのでそれと区別するためにつけるべきという感じですね。ちなみにC言語では .h がヘッダーファイルというものでヘッダーの頭文字 h を取ってるんだと思いますが、僕がC++で使う .hpp というのはC言語のヘッダーファイルと区別するために使っています。)

結局iostreamってどういう便利なやつなの、はやく教えてよ

ごめんね。iostreamはinput/output streamの略ですよ。日本語でおkってなるよね。入力 (input) と出力 (output)に関する便利な機能が入ってて、今回にゃーんプログラムで使ってるのはこの中で cout っていうのと endl っていうやつだね。(先ほどのソースコードもっかい確認したら使われてるのがわかるはず)。

な、なるほど?ところでint mainとかなんなの?

さっきのプログラムの2行目はこうなってますね

int main()

intinteger の略で和訳すると整数ですね。で、main はメイン、主要のって感じですね。整数に関する主要の何かってなんだよ!って感じですよね。しかもなんか()が最後についてるしなんなのと思うでしょう。ネタバレしてしまうとこれは int (整数) が返り値のmain関数です。

関数?なにこれ数学?数学嫌いなんだけど

ごめんね。とにかくこのmain関数、メインって名前がついてるくらいなのでC言語C++では基本的にプログラムが実行されるときまずこのmain関数の中に書いてあることからはじまるんだよ。このmain関数を書かずに適当にそれっぽいコード書いてても上手く実行されないからまずこれを書きましょう。極端に言えばソースコードの全てをこのmainという関数の中で書けば一応動くけど、この中に1000行とか書かれてると他のプログラマさんがとてもおこになります。先ほどのライブラリの話でもありましたよね、便利なやつをわけてしまえば色々なプログラムにも使えたりして便利って。一つのプログラムの中でも書いていくうちに似た処理をする部分が何度も何度も出てくるはずです。そういうときそのまっっっっったく同じ処理をひたすらコピペしてたら行数が増えるだけでスマートじゃないです。そういうときは別の自分で作った関数に入れてあげると何度も書かずにすみます。

C++で関数はこんな風に書きます。

void printNyan()
{

}

関数の呼び出しはこんな感じ。

printNyan();

この事を踏まえてにゃーんプログラムのmain関数の中の処理を自前の関数にうつしてみましょう。

#include <iostream>

// にゃーんを表示する。
void printNyan()
{
    std::cout << "にゃーん" << std::endl;
}

// ここから処理がはじまる。
int main()
{
    printNyan();
    return 0;
}

Wandboxの結果はこの通りです(最初と同じですね)。
http://melpon.org/wandbox/permlink/YvBYn0v6eqIJlav9

返り血って怖っ…何それ…

返り血ではなく返りね。上記のプログラムだと printNyan 関数の返り値は void、main関数の返り値は int です。返り値っていうのは返ってくる値なのですよ(まんま)。printNyan関数を呼ぶとvoidが返ってくる。main関数を呼ぶとintが返ってくる。そういう具合です。

voidってなんや!ってなりますよね。わかります。多分英語ネイティヴでもなります。ここでいう void というのは「何もない」「無」って感じです。厨二病っぽいよね。つまり返り値がないときに使います!printNyan関数は「にゃーん」を表示させてくれますが、特に何も返さないのでvoidにしています。

main 関数はint、つまり整数を返しています。この判別方法はmainの波かっこ({と}のことね)内を探せばわかります。return という英単語があります。return というのは英語で返すって意味なので、これにより返されるものがmain関数の返り値ということになります。この場合 0 が返されていて、0 は整数なのでmain関数の返り値はintですね。

なんでmain関数氏int返してくんの?0って?

C++ではプログラムがまずmain関数を最初に実行するということを先ほど言ったけども、実は返り値もintで決まってるのです、僕がきまぐれでintと0を選んだわけじゃないよ!
実はmain関数の処理が全部上手く行ったかどうかを返り値の整数で判別してるのです。まじか。大丈夫な場合は0、問題があった場合は0以外だとか。

つまりこういうこと:

友人「おいおい、授業中だぞ?お前こんなときにエロ本読んでて大丈夫かよ」
僕「だいじょーぶだって。ぶはー!!!!」(鼻血を出す)
→返り値が血(ゼロ以外)なので異常終了

ただまあ、返り値の種類は一つなので異常なときは血を返して、正常なときはvoidっていう具合にはちょっとできないので(どちらでも値は返す)、異常なときは例えば1を返して正常なときは0を返すとかすると思うよっ。

なんかわかったような…そういえばcoutとかは結局なんだったの

その行だけまだちゃんと説明していなかったね。これね。

std::cout << "にゃーん" << std::endl;

実際の表示は実はこれだけでおkだよっ

std::cout << "にゃーん";

cout は << 演算子とセットで使って、基本的にはその右側にあるもの(この場合にゃーん)を出力してくれる便利なやつだよっ。

へーそう。std::ってついてるのはなんで?かっこつけ?

ちがうちがうw stdはおそらくstandardの略です。日本語でいうと標準ね。あれ?聞き覚えが…。そう、coutとかendlはiostreamライブラリから持ってきた便利なやつで、iostreamは標準ライブラリなのです。標準ライブラリの中の便利機能は基本的にstd名前空間というものの中にあるの。なので使うときはincludeだけすればいいというわけではなく、このようにして std::cout みたいにしてstd名前空間のcoutですよ〜って言わなきゃいけないわけっ。

std名前空間??なにその名前空間っていうのまた厨二病

ごめんねよくわからないよね。C++書くとき、自分の好きな名前空間とか決めることができて、その中で色々機能を実装することによって他の人のライブラリと万が一名前が被ったとき衝突を防げるの。

え、どういうことかって?んー、つまりだよ?

僕が犬を飼っててポチって名付けたとして、C++の標準ライブラリにも万が一ポチという犬が居たとして、それをincludeするとどうなる?
ポチを呼んだら、どっちの犬が駆けつけてくるの?わかんないよね。そういうときのために、標準の犬はstd::ポチという名前にしてくれてると、識別ができて良いということです!(※標準ライブラリにポチはおろか、犬は居ません)

なるほどね。あ、 << 演算子ってなに?見た目変じゃない?小なり小なり?

それね、実は左シフト演算子っていうのだけど、今回の用途では左シフトとは関係がないんだよね。左シフトについて知りたい方は別でググってもらうとして、今回の例で左シフト関係ない理由というのは実は演算子オーバーロードというものがされているからです。ん?まったく意味がわからない?ごめんね、説明する。

足す (+)、引く (-)、掛ける (*)、割る (/)、などは演算子で、 << と >> も演算子なのです。
オーバーロードっていうのは英語で overload って書くのだけど、英単語だけでいうと普通よりも多めに積むというイメージです。
C++では例えば + 演算子は int(整数)2つに対してつかえば足し算してくれます( 5 + 7 だったら結果は 12になるみたいな)。

演算子オーバーロードというのはこの+の定義にさらに自分で付け加えることができるというイメージで、

プログラマ」と「猫」を足すと「すてにゃん」になる、みたいなことを定義できるのです
(普通にオーバーロードせずに + 使ったら何をすればいいのかわからずエラー吐きます)。

ということで、ソースコードに戻りますが、

std::cout << "にゃーん";

このような状況の場合、 "にゃーん"の部分を出力するように << 演算子オーバーロードされているって感じですね!へぇー。

endlのほうは何してるん〜?(´・_・`)

実行結果をみるのがはやいかも。

endlを使ってにゃーんをいっぱい出力した場合:

#include <iostream>

// にゃーんを表示する。
void printNyan()
{
    std::cout << "にゃーん" << std::endl;
}

// ここから処理がはじまる。
int main()
{
    printNyan();
    printNyan();
    printNyan();
    return 0;
}

Wandboxの結果はこの通りです。にゃーんと三回表示されてますね。
http://melpon.org/wandbox/permlink/5CN6AQSlw4ccZbrg

endlを使わずににゃーんをいっぱい出力した場合:

#include <iostream>

// にゃーんを表示する。
void printNyan()
{
    std::cout << "にゃーん";
}

// ここから処理がはじまる。
int main()
{
    printNyan();
    printNyan();
    printNyan();
    return 0;
}

Wandboxの結果はこの通りです。にゃーんと三回表示されているけど改行がないですね。
http://melpon.org/wandbox/permlink/XrKurAOXtke2pVSt

そう、std::endl の役割の1つは改行です。

std::endl は実は改行以外にflushということもしています。std::cout でひたすら出力する場合、例えば出力先がファイルだったりすると一文字ずつそのファイルに書き込むのはとても時間の無駄なので、一旦溜め込んでいくような感じです。 std::endl を呼ぶと改行と一緒に出力先との同期もしてくれるのです。これによりちゃんと出力先ににゃーんが吐き出されます。ちなみに改行をしてほしくないけどflushしてほしい場合は std::flush というのがちゃんとあります。

まとめ

さて、時間の都合でここで終わりですがこの記事であなたはC++のこういうことを理解できるようになったっぽい[要出典]です。

  • (標準)ライブラリやライブラリのincludeの仕方
  • main 関数のこと
  • 関数の基本(定義の仕方や呼び出し方)
  • 関数の返り値
  • 一部の型について(void や int )
  • iostreamライブラリの cout や endlについて
  • 名前空間について
  • 演算子オーバーロードについて

この先どういうことを勉強すればいいかというと例えば上でにゃーんを3回出力していますが、同じ関数呼び出しを3回もしてるのはちょっとスマートじゃないですよね:

printNyan();
printNyan();
printNyan();

こういうことはループに任せるのがよくて、C++や色々なプログラミング言語には for文や while文があるのでそれを使ってみるとか。

あとは世界のナベ○ツ的なことをして、3の倍数と3のつくときだけ「わん」と出力させるようにするとか。こちらは if文とかつかえばいいかもしれない。

とにかく、クリスマスイブなのでケーキ食べて寝ましょう。おやすみなさい。


さて、明日の担当は _EnumHack さんです。お楽しみに!