https://youtu.be/_d55T-NNyGc

\textcolor{pink}{四国めたん: }教師役ですわ

\textcolor{lime}{ずんだもん: }生徒役なのだ
\footnotesize \textcolor{pink}{四国めたん:} こんにちは。四国めたんです
\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ
\footnotesize \textcolor{pink}{四国めたん:} 今回は 修飾子 の続きをお話ししますわ
\footnotesize \textcolor{lime}{ずんだもん:} constとnoexcept以外の 修飾子 か?
\footnotesize \textcolor{pink}{四国めたん:} はい、overrideやfinalとかのキーワードですわね
\footnotesize \textcolor{lime}{ずんだもん:} 待っていたのだ
override
\footnotesize \textcolor{pink}{四国めたん:} まずはoverrideについてお話ししますわね
\footnotesize \textcolor{lime}{ずんだもん:} override?
\footnotesize \textcolor{pink}{四国めたん:} はい、overrideは、メソッドをオーバーライドしていることを示す 修飾子 ですわ
\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ
\footnotesize \textcolor{pink}{四国めたん:} 使い方は、派生クラスでオーバーライドしたメソッドの宣言や定義の後にoverrideを付加しますわ
virtual 型 メソッド名(引数...) override { 処理 };
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお、ソースファイルに定義を行う場合には、ヘッダーファイル側の宣言にのみoverrideを付加しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 両方にoverrideを付加するとどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} エラーとなりますわね
\footnotesize \textcolor{lime}{ずんだもん:} そのあたりはnoexceptと異なるのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみにconstやnoexceptと併用する場合には、const noexcept overrideの順番で記述しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 順番を変えてもOKなのか?
\footnotesize \textcolor{pink}{四国めたん:} いいえ、順番を変えることはできませんわ
\footnotesize \textcolor{lime}{ずんだもん:} ところでオーバーライドするメソッドは、何でもOKなのか?
\footnotesize \textcolor{pink}{四国めたん:} いいえ、オーバーライドするメソッドは、必ず 仮想メソッド でなければなりませんわ
\footnotesize \textcolor{lime}{ずんだもん:} つまり基底クラスのメソッドはvirtualが付加されていなければならないと云うことか...
\footnotesize \textcolor{pink}{四国めたん:} そのとおりですわね
\footnotesize \textcolor{pink}{四国めたん:} とりあえず、以前に 抽象クラス についてお話しした際に使用したサンプルプログラムにoverrideを付加してみましょう
figure.h
#pragma once
#ifndef FIGURE_H
#define FIGURE_H
class Figure {
int border_width_;
unsigned int color_;
public:
Figure(int border_width, unsigned int color)
: border_width_(border_width), color_(color) {}
virtual ~Figure() {}
int BorderWidth() { return border_width_; }
void BorderWidth(int border_width) { border_width_ = border_width; }
unsigned int Color() { return color_; }
void Color(unsigned int color) { color_ = color; }
virtual double Area() const noexcept = 0;
};
#endif // FIGURE_H
circle.h
#pragma once
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
#include "figure.h"
const double kPI = 3.14159265358979323846;
/// @brief 円
class Circle: public Figure {
double diameter_; // 直径
public:
Circle(double diameter) : Figure(1, 0xFF000000), diameter_(diameter) {}
virtual ~Circle() {};
double Diameter() const { return diameter_; }
void Diameter(double diameter) { diameter_ = diameter; }
virtual double Area() const noexcept override;
};
#endif // CIRCLE_H
circle.cpp
double Circle::Area() const noexcept {
double radius = Diameter() / 2.0;
double a = radius * radius * kPI;
return a;
}
hello_world.cpp
#include <iostream>
#include "circle.h"
int main(int argc, char* argv[]) {
Circle c(10.0);
std::cout << "円の直径は" << c.Diameter() << "cmです。" << std::endl;
std::cout << "円の境界線の幅は" << c.BorderWidth() << "mmです。" << std::endl;
std::cout << "円の面積は" << c.Area() << "cm^2です。" << std::endl;
return 0;
}

\footnotesize \textcolor{lime}{ずんだもん:} 解説をお願いするのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、まずFigureクラスのAreaメソッドは 純粋仮想関数 として宣言していますわ
\footnotesize \textcolor{lime}{ずんだもん:} constおよびnoexceptの後に= 0が付加されているのだ
\footnotesize \textcolor{pink}{四国めたん:} そしてCircleクラスでAreaメソッドをオーバーライドしていますわ
\footnotesize \textcolor{lime}{ずんだもん:} メソッドの宣言にoverrideが付加されているのだ
\footnotesize \textcolor{pink}{四国めたん:} ソースファイルのAreaメソッドの定義についてはoverrideを付加していないことに注意ですわ
\footnotesize \textcolor{lime}{ずんだもん:} 付加するとエラーになると言っていたのだ
overrideの目的
\footnotesize \textcolor{lime}{ずんだもん:} ところでoverrideを付加することで、何かメリットがあるのか?
\footnotesize \textcolor{pink}{四国めたん:} overrideはnoexceptと同様に、メソッドの動作に影響を与える 修飾子 ではありませんわ
\footnotesize \textcolor{pink}{四国めたん:} ですので、付加しなくてもメソッドは正常に動作しますわね
\footnotesize \textcolor{lime}{ずんだもん:} では、何でoverrideを付加するのだ?
\footnotesize \textcolor{pink}{四国めたん:} ひとつは、メソッドがオーバーライドされた 仮想メソッド であることを明示できることですわ
\footnotesize \textcolor{lime}{ずんだもん:} 明示したからと云ってメリットが感じられないのだ
\footnotesize \textcolor{pink}{四国めたん:} 確かに簡単なプログラムでは余りメリットに感じませんが、通常のメソッドと 仮想メソッド を複数抱えているクラスを扱う際には意外に便利なのですわ
\footnotesize \textcolor{lime}{ずんだもん:} ふ~ん、そうなのか?
\footnotesize \textcolor{pink}{四国めたん:} もうひとつは、オーバーライドしたメソッドが 仮想メソッド であることを保証できることですわ
\footnotesize \textcolor{lime}{ずんだもん:} う~ん
\footnotesize \textcolor{pink}{四国めたん:} 基底クラスのメソッドにvirtualが付加されていない場合には、コンパイラがエラー、もしくは警告を出力してくれますわ
\footnotesize \textcolor{lime}{ずんだもん:} 間違えて 仮想メソッド 以外をオーバーライドしてしまうことを防げると云うことか
\footnotesize \textcolor{pink}{四国めたん:} そうですわね
\footnotesize \textcolor{pink}{四国めたん:} さらに、基底クラスに存在しないメソッドをオーバーライド?することも防げますわ
\footnotesize \textcolor{lime}{ずんだもん:} そんなことがあるのか?
\footnotesize \textcolor{pink}{四国めたん:} これは結構ある間違いで、基底クラスの 仮想メソッド のメソッド名を間違えてしまった場合に、よく発生しますわね
\footnotesize \textcolor{lime}{ずんだもん:} 例えばFigureクラスのAreaメソッドをCircleクラスでAresメソッドとしてオーバーライド?してしまうとか...
\footnotesize \textcolor{pink}{四国めたん:} そうですわね
\footnotesize \textcolor{pink}{四国めたん:} その場合でもコンパイラがエラー、もしくは警告を出してくれるので、直ぐに修正が可能ですわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほど、なんとなく便利なのはわかったのだ
\footnotesize \textcolor{pink}{四国めたん:} そう云う訳でoverrideについては、積極的に使うようにしましょう
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
final
\footnotesize \textcolor{pink}{四国めたん:} 次はfinalですわね
\footnotesize \textcolor{lime}{ずんだもん:} final?
\footnotesize \textcolor{pink}{四国めたん:} はい、finalは、派生クラスでメソッドをオーバーライドすることを禁止しますわ
\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?
\footnotesize \textcolor{pink}{四国めたん:} 使い方は、基底クラスでオーバーライド可能な 仮想メソッド の宣言や定義の後にfinalを付加しますわ
virtual 型 メソッド名(引数...) final { 処理 };
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお、ソースファイルに定義を行う場合には、ヘッダーファイル側の宣言にのみfinalを付加しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 両方にfinalを付加するとどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} エラーとなりますわね
\footnotesize \textcolor{lime}{ずんだもん:} そのあたりはoverrideと同じなのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみにconstやnoexceptと併用する場合には、const noexcept finalの順番で記述しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 順番を変えてもOKなのか?
\footnotesize \textcolor{pink}{四国めたん:} いいえ、順番を変えることはできませんわ
\footnotesize \textcolor{lime}{ずんだもん:} overrideとfinalについては、どうなのだ?
\footnotesize \textcolor{pink}{四国めたん:} どちらを先に記述しても問題ありませんわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} とりあえず、サンプルプログラムにfinalを付加してみましょう
circle.h
#pragma once
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
#include "figure.h"
const double kPI = 3.14159265358979323846;
/// @brief 円
class Circle: public Figure {
double diameter_; // 直径
public:
Circle(double diameter) : Figure(1, 0xFF000000), diameter_(diameter) {}
virtual ~Circle() {};
double Diameter() const { return diameter_; }
void Diameter(double diameter) { diameter_ = diameter; }
virtual double Area() const noexcept override final;
};
#endif // CIRCLE_H

\footnotesize \textcolor{pink}{四国めたん:} いちおう、CircleクラスのAreaメソッドにfinalを付加してみました。
\footnotesize \textcolor{lime}{ずんだもん:} とくに変わりはないのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、Circleクラスを継承しているクラスがありませんので、finalの効果はありませんわね
\footnotesize \textcolor{lime}{ずんだもん:} 効果が目に見えるようにしてほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} それではFigureクラスのAreaメソッドにfinalを付加してみますわ
figure.h
#pragma once
#ifndef FIGURE_H
#define FIGURE_H
class Figure {
int border_width_;
unsigned int color_;
public:
Figure(int border_width, unsigned int color)
: border_width_(border_width), color_(color) {}
virtual ~Figure() {}
int BorderWidth() { return border_width_; }
void BorderWidth(int border_width) { border_width_ = border_width; }
unsigned int Color() { return color_; }
void Color(unsigned int color) { color_ = color; }
virtual double Area() const noexcept final { return 0.0; }
};
#endif // FIGURE_H
circle.h
#pragma once
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
#include "figure.h"
const double kPI = 3.14159265358979323846;
/// @brief 円
class Circle: public Figure {
double diameter_; // 直径
public:
Circle(double diameter) : Figure(1, 0xFF000000), diameter_(diameter) {}
~Circle() {};
double Diameter() const { return diameter_; }
void Diameter(double diameter) { diameter_ = diameter; }
virtual double Area() const noexcept override;
};
#endif // CIRCLE_H

\footnotesize \textcolor{lime}{ずんだもん:} 解説をお願いするのだ
\footnotesize \textcolor{pink}{四国めたん:} まず、 純粋仮想関数 ではfinalを付加する意味がありませんので、0.0を返すメソッドに変更していますわ
\footnotesize \textcolor{lime}{ずんだもん:} 純粋仮想関数 はオーバーライドを要求するのに、finalでオーバーライドを禁止するのは意味不明なのだ
\footnotesize \textcolor{pink}{四国めたん:} 結果としてCircleクラスのAreaメソッドでオーバーライドした部分でエラーが発生していますわ
\footnotesize \textcolor{lime}{ずんだもん:} CircleクラスのAreaメソッドのfinalは消しているのだ
クラスにfinal
\footnotesize \textcolor{pink}{四国めたん:} ところで、finalはメソッドだけではなく、クラスに対しても付加することが可能ですわ
\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?
\footnotesize \textcolor{pink}{四国めたん:} 使い方はクラス名の後にfinalを付加しますわ
class クラス名 final : public 基底クラス名 { クラス定義 };
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} クラスにfinalを付加すると、クラスの継承自体が禁止されますわ
\footnotesize \textcolor{lime}{ずんだもん:} つまり、派生クラスを作ることができないということなのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、とりあえずFigureクラスにfinalを付加してみましょう
figure.h
#pragma once
#ifndef FIGURE_H
#define FIGURE_H
class Figure final {
int border_width_;
unsigned int color_;
public:
Figure(int border_width, unsigned int color)
: border_width_(border_width), color_(color) {}
virtual ~Figure() {}
int BorderWidth() { return border_width_; }
void BorderWidth(int border_width) { border_width_ = border_width; }
unsigned int Color() { return color_; }
void Color(unsigned int color) { color_ = color; }
virtual double Area() const noexcept { return 0.0; }
};
#endif // FIGURE_H

\footnotesize \textcolor{lime}{ずんだもん:} 解説をお願いするのだ
\footnotesize \textcolor{pink}{四国めたん:} "Figure"の後にfinalを付加し、Areaメソッドからfinalを削除していますわ
\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ
\footnotesize \textcolor{pink}{四国めたん:} 結果としてCircleクラスの継承部分がエラーとなっていますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
finalの目的
\footnotesize \textcolor{lime}{ずんだもん:} ところで、finalを付加するメリットがあるのか?
\footnotesize \textcolor{pink}{四国めたん:} finalはoverrideやnoexceptと同様に、メソッドの動作に影響を与える 修飾子 ではありませんわ
\footnotesize \textcolor{pink}{四国めたん:} ですので、付加しなくてもメソッドやクラスは正常に動作しますわね
\footnotesize \textcolor{lime}{ずんだもん:} たしかにその通りなのだ
\footnotesize \textcolor{pink}{四国めたん:} むしろ、クラスを継承したり、継承クラスでオーバーライドができなくなるので、邪魔に感じることも多いと思いますわ
\footnotesize \textcolor{lime}{ずんだもん:} では、何でfinalを付加するのだ?
\footnotesize \textcolor{pink}{四国めたん:} 主なメリットは、クラスの設計思想を逸脱して派生クラスを作成して欲しくないことを明示できることですわ
\footnotesize \textcolor{lime}{ずんだもん:} クラスの設計思想?
\footnotesize \textcolor{pink}{四国めたん:} はい、クラスの詳細を理解せずに、ほかのひとが派生クラスを作成したり、メソッドをオーバーライドすると、バグの原因になることが多いのですわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} ところで、finalは基本的にヘッダーファイルにのみ記述されますわ
\footnotesize \textcolor{lime}{ずんだもん:} ソースファイル側で記述するとエラーとなるのだ
\footnotesize \textcolor{pink}{四国めたん:} ですので、無理やりオーバーライドしたい場合には、finalを削除してしまえばオーバーライドできてしまいますわ
\footnotesize \textcolor{lime}{ずんだもん:} まぁ、たしかにその通りなのだ
\footnotesize \textcolor{pink}{四国めたん:} つまり、基底クラスの作者の意図を明示することしかできないのですわ
\footnotesize \textcolor{lime}{ずんだもん:} それって意味あるのか?
\footnotesize \textcolor{pink}{四国めたん:} 元々、C++言語はクラスを継承してメソッドをオーバーライドする拡張性、つまり ポリモーフィズム が重要な要素ですわ
\footnotesize \textcolor{lime}{ずんだもん:} うむ
\footnotesize \textcolor{pink}{四国めたん:} それを意図的に殺してしまうfinalは、余程の明確な意図がある場合以外は、使用を控えるべきですわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} 逆に、finalを付加されたクラスやメソッドは、作者が絶対に継承やオーバーライドして欲しくないと考えていることを理解すべきですわね
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
まとめ
\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした
\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ
\footnotesize \textcolor{pink}{四国めたん:} 以上で 修飾子-続き を終わりにしますわ
Discussion