質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

2112閲覧

【C++】 非仮想関数へoverride指定子を付与できない理由

torimingo

総合スコア122

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/04/10 14:33

仮想関数にしないと、override指定子を付与することができないのはなぜでしょうか。
仮想関数でなくても、オーバーライドすることはできるのではないでしょうか。
コードを以下に示します。

c++

1#include <iostream> 2 3class Parent 4{ 5public: 6 void func() 7 {} 8}; 9 10class Child : public Parent 11{ 12public: 13 void func() // overrideを付与することができない 14 { 15 std::cout << "child" << std::endl; 16 } 17}; 18 19int main() 20{ 21 Child child; 22 child.func(); 23 return 0; 24}

上記を実行すると「child」と出力されます。
func()はオーバーライドされていると思うのですが、override指定子を付与することができないのはなぜでしょうか?
func()を仮想関数にすれば、override指定子を付与することができます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

それはオーバーライドじゃなくて遮蔽ですかね。

ただ静的ポリモフィズム(CRTP)の文脈でoverrideつけたくなることはあります。仕方がないのでstatic_assertで代用するわけですが。

投稿2019/04/10 15:18

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/04/10 23:16

ご回答ありがとうございます。 静的ポリモフィズムというのがわからなかったので調べてみたのですが、静的ポリモフィズムは仮想関数が前提ではないですか?? 仮想関数でしたら、overrideを付与することはできますよ。 試しに、以下のページにあるコードのclass Bのvoid echo()にoverrideを付与してみましたが、コンパイルエラーはでませんでした。 https://catindog.hatenablog.com/entry/2014/02/24/172031
torimingo

2019/04/11 02:53 編集

リンク先をすこし読んでみたのですが、静的ポリモフィズムとは、そもそも、継承を使わなくても実装できそうにみえたのですが、そういうわけでもないのでしょうか? リンク先では、myclass1クラスとmyclass2クラスは、Interfaceクラスを継承していますが、静的ポリモフィズムでは、これは必須なのでしょうか? テンプレートに異なるクラスを渡すことで多様性を実現しているだけではないのでしょうか・・・? テンプレートのなかにある関数をvirtualにできないというのは、今回の質問内容とは異なるもので、ちょっと時間がないので調べられません。 時間ないので、ちゃんとみれてませんが、全然見当違いのこと言ってたら、すいません!
yumetodo

2019/04/11 04:53

リンク先で言及されているので御覧ください("非常に簡単ですが、色々と問題があります。"以下)。
torimingo

2019/04/11 07:04 編集

失礼しました、リンク先の言及後のコードしか見ていませんでした。 言及後のコードは、構文的に?ちょっと難しくて、改善点や利点がよくわかりませんでした。 (言及後のコードで、Printerクラスを配列で管理できないようにみえるのですが、管理できるのでしょうか・・・) いずれにしても、本題から少し脱線している気がしますので、この辺までとさせてください。 静的ポリモフィズムについては、必要になったときにまた勉強してみようと思います。
guest

0

ベストアンサー

仮想関数でなくても、オーバーライドすることはできるのではないでしょうか。

いいえ。仮想関数でないメンバ関数に対しては、「オーバーライド(override)」ではなく「隠蔽(hiding)」が行われます。そしてクラス継承を用いたプログラム設計では、この「隠蔽」はプログラマが望まない動作になりがちです。

そもそも override キーワードは、プログラマのミスによって「オーバーライド」がうっかり「隠蔽」にならないようにする 安全装置 として導入されました。cpprefjpサイトの解説 も参照ください。

この override キーワードは、新しい機能性を提供する(=できることが増えて嬉しい)ものではありません。既存ソースから override キーワードを削除してもプログラムの意味自体は全く変化しませんが、ソースコード自身の自己記述能力の向上、将来的な設計変更に対する堅牢性の向上に大きく貢献するものです。


下記は、override キーワードがあればコンパイルエラーとして早期検知できたシナリオです。説明用サンプルなので大きなメリットには思えないかもしれませんが、ある程度規模の大きいコードベースに対するリファクタリング作業等では大変有用と思います。

C++

1class Base { 2public: 3 // 基底クラスの仮想関数を定義 4 virtual void process(int); 5}; 6 7class Derived: public Base { 8public: 9 // 仮想関数を「オーバーライド」したつもり... 10 virtual void process(short) /*override*/; 11 // 実際には引数パラメータが一致しないので 12 // 「隠蔽(hiding)」になってしまっている 13}; 14 15void func(Base& obj) 16{ 17 // 引数objに派生クラスDerivedインスタンスが指定された場合、 18 // 意図としてはオーバライド先Derived::processが呼ばれてほしい。 19 // しかし前述のミスによりBase::processが呼び出されてしまう。 20 obj.process(42); 21}

投稿2019/04/12 02:25

編集2019/04/12 02:41
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

torimingo

2019/04/12 07:33

ご回答をありがとうございました。 例を挙げて頂いて、理解できました。
guest

0

overrideが「仮想クラス関数のオーバーライドを行うこと」を明示する(うっかりミスをコンパイルエラーにする)ためのキーワードだから,ではないかと.

投稿2019/04/10 15:16

編集2019/04/12 02:09
fana

総合スコア11647

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

c++

1#include<iostream> 2using namespace std; 3 4struct Base{ 5 void say(){ 6 cout << "Base::say()" << endl; 7 } 8 void hello(int){ 9 cout << "Base::hello(int)" << endl; 10 } 11}; 12 13struct VBase{ 14 virtual void say(){ 15 cout << "VBase::say()" << endl; 16 } 17 virtual void hello(int){ 18 cout << "VBase::hello(int)" << endl; 19 } 20}; 21 22struct Derived : public Base { 23 void say(){ 24 cout << "Derived::say()" << endl; 25 } 26 void hello(char*){ 27 cout << "Derived::hello(char*)" << endl; 28 } 29}; 30 31struct VDerived : public VBase { 32 void say() override { 33 cout << "VDerived::say()" << endl; 34 } 35 virtual void hello(char*) /* ここにoverrideをつけるとコンパイルエラーになる */ { 36 cout << "VDerived::hello(char*)" << endl; 37 } 38}; 39 40 41int main(){ 42 Derived d; 43 VDerived v; 44 Base *p = &d; VBase *q = &v; // アップキャスト 45 cout << "---正しくoverrideできている場合---" << endl; 46 d.say(); v.say(); 47 p->say(); q->say(); 48 49 cout << "---overrideに失敗している場合---" << endl; 50 d.hello(0); v.hello(0); 51 p->hello(0); q->hello(0); 52}

text

1---正しくoverrideできている場合--- 2Derived::say() 3VDerived::say() 4Base::say() 5VDerived::say() 6---overrideに失敗している場合--- 7Derived::hello(char*) 8VDerived::hello(char*) 9Base::hello(int) 10VBase::hello(int)

基底クラスにおいて仮想関数でない場合は、アップキャストすると基底クラスの関数が呼ばれるが
仮想関数であった場合、正しくオーバーライドできているかで呼び出される関数が変化します。

よってオーバーライドできている事を保証するために仮想関数にはoverride指定子があるわけです。

投稿2019/04/10 22:11

asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問