2016-04-27 14 views
7

最終的にC++ 11が追加されました。C++の最終版は、すべての面で最終版を意味しますか?

最後に!

  • は、クラスが非継承します:

    私はfinalは、2つのことを行い理解しています。

  • クラス内の(仮想)関数を(派生クラス内で)オーバーライドできないようにします。

これらはどちらも互いに独立しているようです。しかし、例えば次のように取る:

class Foo 
{ 
    public: 
    virtual void bar() 
    { 
     //do something unimportant. 
    } 
}; 
class Baz final : public Foo 
{ 
    public: 
    void bar() /*final*/ override 
    { 
     //do something more important than Foo's bar. 
    } 
}; 

以上のことから、私はBazfinalいると信じて、私はそのvirtualメンバ関数barfinalであることを指定する必要はありません。 Bazは継承できないので、barをオーバーライドするという問題は範囲外になります。しかし、私のコンパイラVC + + 2015は、これについて非常に静かです。私は現時点ではこれを他の誰かにテストしていません。

誰かがこのトピックについて少し明るい話をすることができたらうれしいです。標準からの引用(ある場合)は非常に高く評価されます。また、私が気づいていないコーナーケースについても、論理的な信念が損なわれる可能性があることを述べてください。

だから、私の質問は次のとおりです。final classは、暗黙のうちにもfinalであることをそのvirtual機能を暗示していますか?すべき?どうか明らかにしてください。


final機能は素晴らしい最適化されデ仮想化、のための資格になるので、私はこれを求めています理由があります。どんな助けもありがとうございます。

+2

最終機能は、機能が最終であるものと静的タイプが一致する場合にのみ、仮想化解除されます。 Happenesはめったになく、最初はバーチャルが必要ないという事実を示していることがよくあります。 – SergeyA

+0

@ SergeyAはい。だから私は資格を書いた。 –

+2

コンパイラが仮想呼び出しを必要としないことを保証できれば、(最適化として)仮想呼び出しを実行しません。コンパイラは賢明で、すでにfinalの導入前にこれを行っていました。しかし、今はもっと簡単だと思います。 –

答えて

8

私がこれを求めているのは、最終機能が非最適化に適しているためです。これは最適な最適化です。

ですか? 「非仮想化」はC++標準の一部ではありません。少なくとも、実際はそうではありません。

仮想化の解除は、実装が "標準と同じように"動作している限り、実装が実行できることを「as if」ルールの結果に過ぎません。コンパイラは仮想メンバ関数への特定のコールは、多形型を介して、紛れもなく、その関数の特定のバージョンをコールすることをコンパイル時に検出することができる場合

、仮想ディスパッチロジックを使用しないようにさせ、静的に関数を呼び出します。コンパイラは、これが呼び出されたはずの関数であることを証明することができるので、仮想ディスパッチングロジックを使用した場合と同様に動作します。

このように、標準では、非仮想化の許可/禁止を定義していません。コンパイラは、仮想型へのポインタをとるクラスをインライン展開する際に、渡されるポインタが、インライン化されている関数で宣言されたスタック変数localを指していることがあります。または、コンパイラは特定の多形ポインタ/参照の起点に特定のインライン/コールグラフをトレースすることができます。そのような場合、コンパイラはその型への呼び出しを非仮想化できます。しかし、そうするには十分スマートな場合に限ります。

finalと宣言されているかどうかにかかわらず、コンパイラはすべての仮想関数呼び出しをfinalクラスに仮想化しますか?そうかもしれない。それはできません。それは、多態型でfinalと宣言されたメソッドへの呼び出しをデバッグすることさえできません。これは有効な(特に明るくない場合)実装です。

質問は実装固有のものです。コンパイラによって異なることがあります。

しかし、あなたが指摘したように、finalと宣言されているクラスは、finalクラス型へのポインタ/参照へのすべての呼び出しをデバッガにコンパイルするのに十分な情報でなければなりません。コンパイラがそうしないと、それは標準の実装ではなく、実装品質の問題です。

+0

仮想化メカニズム全体(仮想テーブルとポインタで行われる)は、標準の一部ではありません。実装者が実装した実装の詳細について、実装者が詳細を投稿することを期待していました。とにかく、明確な答えは+1です。 –

4

ドラフトここ[class.virtual/4]からC++標準引用する:いくつかのクラスBで仮想関数fのvirt-指定finalB機能D::fから派生したクラスD中でマークされている場合

B::fをオーバーライドすると、プログラムは不正です。

そして、ここで[class/3]

クラスはクラスのvirt-指定finalでマークされ、それがベース句ベース型指定子として表示されている場合([class.derived]節)、プログラムは不正です。

したがって、質問に答えて、

finalclassは、暗黙のうちにもfinalであることをそのvirtual機能を暗示していますか?すべき?どうか明らかにしてください。

少なくとも正式ではありません。どちらのルールに違反しようとしても、どちらの場合も同じ結果になります。プログラムは不正な形式であり、コンパイルされません。 A final classは、そのクラスを派生することができないことを意味します。そのため、その結果、そのvirtualメソッドを上書きすることはできません。

すべきですか?少なくとも正式には、おそらくそうではありません。彼らは関連していますが、彼らは同じことではありません。正式に他方を暗示することを正式に必要とする必要もなく、その効果は自然に続く。すべての違反には同じ結果があり、コンパイルに失敗します(うまくいけば、2つを区別する適切なエラーメッセージが表示されます)。


仮想通話のクエリと非仮想化の動機付けに触れてください。これは、クラスまたはメソッドのfinalによっていつもすぐに影響を受けるとは限りません(ヘルプを提供していますが)。仮想関数とクラス階層の通常の規則が適用されます。

実行時に特定のメソッドが常に呼び出される場合(たとえば、自動オブジェクト、つまり「スタック上」)、コンパイラはメソッドが最終的であるかどうかに関係なく、an optimisation anywayを適用できます。これらの最適化は、元のコードが実行された場合に観察可能な振る舞いがそのままである限り、コンパイラがapply any transformationを許可するas-ifルールの下にあります。

+0

?どのように形成されていますか? 'finalクラス'は、 'final'として**実質的に継承されたメンバ関数**を暗示することになっています。上記の例は両方のテストケースでコンパイルされます: 'final'指定子が仮想関数にアタッチされているときとそうでないとき(エラー/警告/情報メッセージはまったくありません)。説明してください。 –

+0

はい、あなたが(尋ねられるように)標準的な言葉遣いは、それが最終的な方法を上書きしようとしたとき、または最終的なクラスをベースとして試みたときに関係します。それがファイナルの目的です。最終的なキーワードを組み合わせることはできますが、問題はありません.2つのケースが同じことを意味するわけではありません。将来のコードのメンテナンスについて懸念がある場合は、アドバイスを受けることもできます。あなたが言及している最適化は実装上の問題であり、最終版が標準に追加されるずっと前です。 – Niall

関連する問題