https://youtu.be/dDy_iAMCA5k

四国めたん:教師役ですわ

ずんだもん:生徒役なのだ
四国めたん: こんにちは。四国めたんです
ずんだもん: ずんだもんなのだ。こんにちはなのだ
四国めたん: 今回は関数の オーバーロード についてお話ししますわ
ずんだもん: オーバーロード ?
四国めたん: 以前の回でゲッターやセッター、コンストラクタなどで同じ名前のメソッドを定義していたのを覚えていますか?
ずんだもん: おぼえているのだ
四国めたん: 同じ名前の関数やメソッドを定義できる仕組みが オーバーロード ですわ
ずんだもん: 詳しく教えて欲しいのだ
関数名を使い回わそう
四国めたん: 前々回までの説明で、 ゲッター や セッター 、 コンストラクタ などについて、同じメソッド名で複数のメソッドを宣言、定義していましたわ
ずんだもん: 不思議に思っていたのだ
四国めたん: C言語では明らかにエラーとなってしまいますが、C++言語では問題なく使えていますわね
ずんだもん: そうなのだ
四国めたん: これはクラス中のメソッドだけではなく、メイン関数を除く一般の関数でも同じですわ
ずんだもん: そうなのか?
四国めたん: はい、このように同じ関数名で複数の関数を宣言、定義することを オーバーロード と言いますわ
ずんだもん: オーバーロード ?
四国めたん: オーバーロード 可能な条件はいくつかありますが、基本的には「引数の数もしくは型が異なる」場合に可能ですわね
ずんだもん: なるほどなのだ
四国めたん: まぁ、関数やメソッドを呼び出す際に、どの関数を呼び出すかを特定できるならOKだと思いますわ
四国めたん: とりあえず実例を見てみましょう

四国めたん: 【C言語超入門】 第16回 関数の解説の際にエラーとなったプログラム例をC++言語向けに修正したものですわ
ずんだもん: あの時にはエラーがたくさん出ていたのだ
四国めたん: はい、今回はadd
関数を2つ定義していますが、正常に動作していますわ
ずんだもん: おもしろいのだ
四国めたん: これはadd
関数に渡す引数の値がint
かfloat
かで区別がつくからですわ
ずんだもん: たしかにその通りなのだ
四国めたん: ここでadd
関数の引数を全てfloat
型にして、戻り値のみ異なる関数としてみましょう

ずんだもん: 今回は「E0311 戻り値の型だけで識別される関数はオーバーロードできません」と云うエラーが出ているのだ
四国めたん: 結局、戻り値の型が異なっていても、引数が同じであれば関数やメソッドを オーバーロード はできませんわ
ずんだもん: なるほどなのだ
名前空間で区別しましょう
ずんだもん: 結局、引数が同じ関数を複数同時に定義もしくは宣言することはできないのか...
四国めたん: まぁ、方法はありますわ
四国めたん: 例えば会社などでプロジェクトを組んで、複数のプログラマーが一緒にプログラムを組む場合、C言語などでは関数名が被らないようにしなければなりませんわ
ずんだもん: 定数の名前や構造体名なども同じなのだ
四国めたん: そんな場合には、例えば個々のプログラマーにIDを割り振って、名前の前にIDを付加して区別するなどの工夫をしますわね
ずんだもん: Add
関数をZundaAdd
と云う名前にするとか...
四国めたん: そうですわね
ずんだもん: C++言語でも同じように、 オーバーロード が可能でも引数と関数名がかぶってしまうことがありそうなのだ
四国めたん: はい、そのためC++言語では 名前空間 もしくは namespace という、C言語に比べて少し洗練された機能が追加されていますわ
ずんだもん: 名前空間 ?
四国めたん: 今までのプログラム例でも使ってきましたが、std::cout
のstd
などが、その一例ですわ
ずんだもん: あぁ、あの...
四国めたん: 名前空間 を指定することで同じ名前の関数を区別することができますわ
ずんだもん: なるほどなのだ
名前空間の指定は波括弧で括るだけですよ
ずんだもん: 名前空間 の指定はどのようにおこなうのだ?
四国めたん: 方法はシンプルで、このようにしますわ
四国めたん: 関数やクラス、構造体、外部変数、定数などを波括弧"{}"で括ってnamespace
キーワードに続けて"名前空間名"を指定するだけですわ
ずんだもん: 結構、簡単なのだ
四国めたん: はい、"名前空間名"は基本的にスネークケースで記述することが推奨されているようですわ
ずんだもん: スネークケース?
四国めたん: いわゆる小文字の英数字とアンダースコアのみで構成される名前ですわ
ずんだもん: 名前に決まりはあるのか?
四国めたん: 名前のつけ方自体は仕様ではありませんので、好きなように名前をつけてもOKかと思いますわ
ずんだもん: たとえば?
四国めたん: 会社名やプログラム名、個人名などにシリアル番号を付加したものなどは判りやすいかと思いますわ
ずんだもん: なるほどなのだ
四国めたん: ただstd
という名前空間名はC++言語に付随する 標準テンプレートライブラリ でデフォルトで使われている名前なので、使わないようにしましょう
ずんだもん: りょうかいなのだ
四国めたん: ちなみに#define
で定義された定数に関しては、波括弧内に記述しても名前空間からは完全に独立して処理されますわ
ずんだもん: なるほどなのだ
名前空間内のオブジェクト指定は::を使います
ずんだもん: では 名前空間 内のオブジェクト、例えばクラスや定数、外部変数を指定するにはどうすればいいのだ?
四国めたん: 基本的にはstd::cout
を見れば判る通り、コロンを2つつなげた スコープ解決演算子 "::"を使いますわ
ずんだもん: スコープ解決演算子 ?
四国めたん: はい、名前空間名::クラス名
のように指定しますわ
ずんだもん: つまりstd::cout
は"std" 名前空間 に属する外部変数"cout"と云うことか
四国めたん: その通りですわ
名前空間を実際に使ってみよう
四国めたん: すでにプログラム例では 名前空間 を使っていますが、改めて 名前空間 を使ってadd
関数を書き直してみますわ
ずんだもん: おねがいするのだ

ずんだもん: お~、関数名のバッティングが回避されているのだ
四国めたん: はい、int
型の変数をfloat
型の引数に渡すことでワーニングは出ていますが、同じadd
という関数名でのバッティングは回避されていますわ
いちいち名前空間を指定するのは面倒です!
ずんだもん: ところでバッティングしない関数名や外部変数名にまで スコープ解決演算子 を使って 名前空間 を指定するのは面倒なのだ
四国めたん: たしかにその通りですわね
四国めたん: そこでC++言語ではusing
というキーワードを用意していますわ
ずんだもん: using
?
四国めたん: はい、一般的には usingディレクティブ と呼ばれていますわ
ずんだもん: どのように使うのだ?
四国めたん: こんな感じで使いますわ
ずんだもん: なるほど、using namespace
の後に 名前空間 の名前を記述するのか
四国めたん: はい、機能としてはusing
以降の関数やクラス、外部変数などについて、指定した名前空間名を省略できますわ
ずんだもん: お~、便利なのだ
四国めたん: 当然ですが、 名前空間 を省略しても一意に決められることが前提ですわ
ずんだもん: なるほどなのだ
四国めたん: それではプログラム例のstd
名前空間を省略してみましょう

ずんだもん: 問題なく動作しているのだ
四国めたん: using namespace std;
により、今までのstd::cout
やstd::endl
からstd::
を省いてcout
やendl
とすることができていますわ
ずんだもん: なるほどなのだ
四国めたん: なおusing
を使った 名前空間 の省略ですが、多用はお勧めしませんわ
ずんだもん: そうなのか?
四国めたん: はい、大きいプログラムでは関数名やクラス名の重複などは意外に発生するものですわ
ずんだもん: その通りなのだ
四国めたん: using
を使った 名前空間 の省略を行うと、関数名やクラス名の重複によって訳のわからないバグなどが発生する場合があるのですわ
ずんだもん: それは大変なのだ
四国めたん: ですので多少面倒ではありますが、関数名などは省略せずにしっかりと 名前空間 の指定を行うようにしてくださいね
ずんだもん: りょうかいなのだ
まとめ
四国めたん: お疲れさまでした
ずんだもん: おつかれさまなのだ
四国めたん: 以上で オーバーロードと名前空間 の説明を終わりますわ
Discussion