Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Effective modern C++ 勉強会 #3 Item 12

1,656 views

Published on

2015/03/25 Effective modern C++勉強会の発表資料です。

Published in: Software
  • Be the first to comment

Effective modern C++ 勉強会 #3 Item 12

  1. 1. Effective Modern C++ Item 12 Effective Modern C++ 勉強会#3 2015/03/25 福田圭祐 @keisukefukuda
  2. 2. Item 12: Declare overriding functions override
  3. 3. 概要 基底クラスの関数をoverrideしたいときは、新たに追加 されたoverrideキーワードを使おう (おまけ) メンバ関数のreference qualifierについて
  4. 4. reference qualifierについて 先に説明 メンバ関数宣言にreference qualifierがついていると、 *thisが右辺値か左辺値かによって呼び分けられる関数を 作ることができる class Widget { public: void f() &; void f() &&; }; Widget().f(); // f()&& Widget w; w.f(); // f() &
  5. 5. reference qualifierの例 class Widget { public: using DataType = std::vector<double>; DataType &data() { return values; } private: DataType values; }; ... // Widgetを作る関数 Widget makeWidget(); // ふつう Widget w; auto vals1 = w.data(); // Widgetオブジェクトは右辺値なので // vectorのコピーが無駄 auto vals2 = makeWidget().data();
  6. 6. reference qualifierの例 class Widget { public: using DataType = std::vector<double>; DataType &data() & { return values; } DataType data() && { return std::move(values); } private: DataType values; }; // lvalue overloadが呼ばれる Widget w; auto vals1 = w.data(); // rvalue overloadが呼ばれる auto vals2 = makeWidget().data();
  7. 7. virtual関数のoverride virtual関数のoverrideが起こる条件 (C++98 & C++11共通) • 基底クラスの関数がvirtual • 基底クラスと派生クラスで関数名が同一 • 仮引数の型も同一 • const qualifierも同一 • 戻り値の型と例外指定がcompatible
  8. 8. 戻り値の型がcompatibleとは 基底クラスと派生クラスの関数 TB B::f() TD D::f() があるとき、以下の条件が満たされれば、両者の戻り値の 型はcovariantである • TB,TDが両方ともポインタor参照型である • TBが、TDの直接or間接の基底クラスである • cv-qualifierが同一 or TBの方が厳しい
  9. 9. 例外指定がcompatibleとは 基底クラスと派生クラスの関数 TB B::f() throws(…) TD D::f() throws(…) があるとき、 { B::f()が投げる例外 } ⊃ {D::f()が投げる例外 } なら、例外指定はcompatible ※ただし例外指定はオワコン
  10. 10. virtual関数のoverride virtual関数のoverrideが起こる条件 (C++98 & C++11共通) • 基底クラスの関数がvirtual • 基底クラスと派生クラスで関数名が同一 • 仮引数の型も同一 • const qualifierも同一 • 戻り値の型と例外指定がcompatible (C++11から) • reference qualifierが同一
  11. 11. 間違いの例 class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Drived : public Base { public: virtual void mf1(); virtual void mf2(unsigned int x); virtual void mf3() &&; void mf4() const; };
  12. 12. 間違いの例 class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Drived : public Base { public: virtual void mf1(); virtual void mf2(unsigned int x); virtual void mf3() &&; void mf4() const; }; const qualifierが違う
  13. 13. 間違いの例 class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Drived : public Base { public: virtual void mf1(); virtual void mf2(unsigned int x); virtual void mf3() &&; void mf4() const; }; const qualifierが違う 仮引数の型が違う
  14. 14. 間違いの例 class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Drived : public Base { public: virtual void mf1(); virtual void mf2(unsigned int x); virtual void mf3() &&; void mf4() const; }; const qualifierが違う 仮引数の型が違う reference qualifierが違う
  15. 15. 間違いの例 class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Drived : public Base { public: virtual void mf1(); virtual void mf2(unsigned int x); virtual void mf3() &&; void mf4() const; }; const qualifierが違う 仮引数の型が違う reference qualifierが違う 基底クラスでvirtual宣言を忘れている
  16. 16. virtual関数のoverrideは間違いやすい でもコンパイラが警告出すでしょ? → 出さないコンパイラもある mf1 mf2 mf3 mf4 g++ 4.8.2 warning※ warning※ warning※ g++ 4.9.2 warning※ warning※ warning※ clang++ 3.5 warning warning warning ※-Wall, -Wextra, -Weffc++(4.9.2)ではダメで、陽に-Woverloaded-virtualを指定 やってみた ※g++は、-Wsuggest-override というのも有るらしいが、4.9.2では認識されなかった
  17. 17. virtual関数のoverrideは間違いやすい 重要だが間違いやすいので、C++11ではoverrideキーワー ドが追加された class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; void mf4() const; }; class Drived : public Base { public: virtual void mf1() override; virtual void mf2(unsigned int x) override; virtual void mf3() && override; void mf4() const override; }; error: 'virtual void Drived::mf1()' marked override, but does not override virtual void mf1() override; ^ ちゃんとエラーになる
  18. 18. virtual関数のoverrideは間違いやすい 重要だが間違いやすいので、C++11ではoverrideキーワー ドが追加された // overrideを使った正しいコード class Base { public: virtual void mf1() const; virtual void mf2(int x); virtual void mf3() &; virtual void mf4() const; }; class Drived : public Base { public: virtual void mf1() override; virtual void mf2(unsigned int x) override; virtual void mf3() && override; void mf4() const override; };
  19. 19. overrideを使うメリット overrideキーワードを使うことのメリット: • 間違いが減る • 基底クラスのvirtual関数のシグネチャを変更する際に、影響範囲 の見積もりが楽 override, final は contextual keyword =関数シグネチャの末尾以外では予約語ではない class Widget { public: void override(); // →OK };
  20. 20. Things to remember • overrideキーワードを使おう • reference qualifiersを使うと、*thisが左辺値と右 辺値の時の挙動を変えることができる

×