はじめに
C++11では、文脈依存キーワードfinal
とoverride
が追加されました。ここでoverride
について見てみます。
問題
次の2つのコードは合法でしょうか?違法でしょうか?
struct B {
void f(int);
};
struct D : B {
void f(int) override;//合法?違法?
};
struct B {
virtual void f(int);
};
struct D : B {
void f(int) override;//合法?違法?
};
規格書を読みつつ答えよう
1つめ
違法です
根拠を見てみましょう。
10.3 Virtual functions [class.virtual]
5 If a virtual function is marked with the virt-specifier override and does not override a member function of
a base class, the program is ill-formed. [ Example:
struct B {
virtual void f(int);
};
struct D : B {
virtual void f(long) override; // error: wrong signature overriding B::f
virtual void f(int) override; // OK
};
—end example ]
override
指定子は仮想関数につけるものです。もう一度コードを見ると
struct B {
void f(int);
};
struct D : B {
void f(int) override;//合法?違法?
};
D::f
は仮想関数ではありません。よってoverride
指定子はつけられません。
2つめ
合法です
根拠を見てみましょう。
10.3 Virtual functions [class.virtual]
2 If a virtual member function vf is declared in a class
Base
and in a classDerived
, derived directly or indirectly fromBase
, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) asBase::vf
is declared, thenDerived::vf
is also virtual (whether or not it is so declared) and it overridesBase::vf
もう一度コードを見てみましょう
struct B {
virtual void f(int);
};
struct D : B {
void f(int) override;//合法?違法?
};
D::f
は一見仮想関数ではないように見えますが、基底クラスB
に同じシグネチャー(名前や引数とか)の仮想メンバー関数B::f
があります。なのでD::f
は仮想関数となり、同じシグネチャーなのでオーバーライドしているため、override
指定子をつけることができます。
結論
struct B {
virtual void f(int);
};
struct D : B {
void f(int) override;//これは仮想関数
};
ところでcpprefjpをみてみようか
//基底クラス
class base {
virtual void func_final() final;
virtual void func_virt();
virtual void func_virt_int(int a);
void func_non_virt();
};
//派生クラス
class derived : public base {
//NG, final メンバ関数はオーバーライドできない
void func_final();
//OK, オーバーライドできている
void func_virt() override;
//NG, 引数の個数、型が違っており、オーバーライドできてない
void func_virt_int(short a) override;
//NG, 基底クラスの func_non_virt() は仮想関数では無いので、オーバーライドできていない
void func_non_virt() override;
};
がっつり書いてあったぞい。
経緯
最初は
http://qiita.com/knknkn1162/items/9a65ca65b558f31121f0
にツッコミを入れようと規格書を読んでいた。
struct B {
— yumetodo-C++erだけど化学科 (@yumetodo) 2016年10月27日
virtual void f(int);
};
struct D : B {
void f(int) override;
};
virtualついてないメンバー関数にoverride指定つけるのって合法なの?
@yumetodo 基底クラスでvirtualならシグネチャーが同一の関数は暗黙的にvirtualなので合法
— 白山風露 (@kazatsuyu) 2016年10月27日
>基底クラスでvirtualならシグネチャーが同一の関数は暗黙的にvirtual
— yumetodo-C++erだけど化学科 (@yumetodo) 2016年10月27日
(つд⊂)ゴシゴシ
>暗黙的にvirtual
・・・!?なにそれ!おどろ木ももの木さんしょの木! https://t.co/SM2REc7Muc
本当に @yumetodo 氏は継承には弱いな https://t.co/qT8qptPOFD
— 白山風露 (@kazatsuyu) 2016年10月27日
継承なんて大嫌いだーーーーー!!!! https://t.co/mu3tBaSQlM
— yumetodo-C++erだけど化学科 (@yumetodo) 2016年10月27日
規格書読みに行ったら§ 10.3の1と3に本当に書いてあった。 https://t.co/mu3tBaSQlM
— yumetodo-C++erだけど化学科 (@yumetodo) 2016年10月27日
つーか一度見たはずのcpprefjpにもきっちり書いてあったorzhttps://t.co/G4C9vag2JK
— yumetodo-C++erだけど化学科 (@yumetodo) 2016年10月27日
注意力散漫だった https://t.co/SM2REc7Muc
C++の会Slackにて
そうですね。補足すると、当然ながらデストラクタも同様です。