2016-04-02 18 views
2

私は仮想デストラクタを持つ純粋な抽象基本クラスを宣言したいと思います。私はこれを行う3つの方法を知っていますが、私はどちらが最良か、なぜなら分かりません。C++でインターフェイスのような純粋な抽象基本クラスを実装するためのベストプラクティスは?

私の目標は、ベストプラクティスのC++ 11スタイルで、抽象基本クラスインターフェイスを最適な実行時パフォーマンスで実装することです。特に、私はノーオペレーションのデストラクタのインライン化/削除をお勧めします。重複したvtableを生成しない実装を選択するか、または警告を抑制する情​​報に基づいた決定を行うことによって、重複するvtableに関連する警告を排除したいと思います。

オプション#1

/// A.h: 

class A { 
public: 
    virtual ~A() {} 
    virtual int f() = 0; 
}; 

オプション#2

/// A.h: 

class A { 
public: 
    virtual ~A(); 
    virtual int f() = 0; 
}; 

/// A.cpp: 

A::~A() {} 

オプション#:ここ

は、私が知っている抽象基本クラスを実装するための3つの方法があります3

/// A.h: 

class A { 
public: 
    virtual ~A() = default; 
    virtual int f() = 0; 
}; 

これらの唯一のオプションはありますか?

#1、#2、#3のどれがベストプラクティスと見なされますか?トレードオフ(例:ランタイムとコンパイル時のパフォーマンス)がある場合は、それらを記述してください。

オプション#1を使用すると、インラインデストラクタはインライン化されますか?

オプション#1はvtableをすべての翻訳単位に入れることを理解します。オプション#1は、clangで警告が-Wweak-vtablesを生成し、gcc [1]の "曖昧なリンケージ"カテゴリでカバーされます。オプション#3はclang警告を生成しません - これはオプション#3がvtableを生成しないことを意味しますか?

どのように正確にオプション#3は、他のオプションの違いは?

その他の質問が打ち鳴らすの警告に対する同様の問題を議論してきたが、私は特に、ベストプラクティスとその理由であると考えられるオプション対処質問を見つけることができませんでした。

[1] https://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html

+2

[CppCoreGuidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)には、このタイプの質問に関する良いセクションがあり、その価値があるかもしれませんあなたは読むべきです。 – Maikel

+0

私は科学的計算を行い、私の領域ではこれらの変種のどれも多型には使用されていません。本当にパフォーマンス重視のタスクについては、[static polymorphism](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)または[Barton-Nackman-Trick](https://en.wikipedia.org/wiki)をご覧ください。/Barton%E2%80%93Nackman_trick) – Maikel

+0

@Maikelはい、私はそれらのテクニックも使用しています。しかし、この質問は、単純なvtableベースの多態性手法に関するものです。 –

答えて

1

のベストプラクティス(私が担当していたときに、少なくとも):

struct A { 

    // 
    // keep move semantics available - rule of 0, 3, or 5 
    // in this case, 5 because we defined a destructor. 
    // 
    A(const A&) = default; 
    A(A&&) = default; 
    A& operator=(const A&) = default; 
    A& operator=(A&&) = default; 
    virtual ~A() = default; 

    // non-polymorphic interface in terms of private polymorphic 
    // implementation 

    int f() 
    try 
    { 
     // possibly lock a mutex here? 
     // possibly some setup code, logging, bookkeeping? 
     return f_impl(); 
    } 
    catch(const std::exception& e) { 
     // log the nested exception hierarchy 
     std::throw_with_nested(std::runtime_error(__func__)); 
    } 

private: 

    virtual int f_impl() = 0; 

}; 

はなぜfに対するtry-catchブロックを持っているあなたの意見ではそれが重要です()? - エインポクラム16分前

@einpoklum私はあなたに尋ねられてうれしいです。あなたはすべてのメソッドと、すべての機能でこれを行うと、関数名(および関連する引数)を含むネストされた例外をスローした場合、それはあなたが最終的に例外をキャッチするとき、あなたは、ログファイルにすべてのネストされた例外をアンラップまたはことができることを意味しているのでCERRあなたが問題に正確に向いて完璧なスタックトレースを取得します。ネストされた例外をアンラップため

参照:

http://en.cppreference.com/w/cpp/error/throw_with_nested

その傷ついたパフォーマンスをしないのですか?

少しでも少しです。

しかし、それは起こったなぜあなたは見当がつかない方法や問題を再現しようとする必要があるために、すべての機能

それははるかに大きな痛みをだへの関数tryブロックを追加するための痛みだし、文脈についての手掛かりはありません。これを信用してください...

+0

あなたの意見では 'f()'のtry-catchブロックを持つことがなぜ重要ですか? – einpoklum

+0

@einpoklum私はあなたに尋ねられてうれしいです。これは、すべてのメソッドとすべての関数でこれを行い、関数名(および関連する引数)を含む入れ子にされた例外をスローすると、最後に例外をキャッチすると、ネストされたすべての例外がログファイルに展開されるか、セルとあなたは、問題を正確に指し示す完全なスタックトレースを取得します。 –

+0

通常の例外よりもネストされた例外が優先される理由について説明しました。しかし、なぜ例外がありますか?誰も何も投げていないと誰も言わなかった。ベースクラス/ mixinのすべての仮想メソッドでtry-catchブロックを持つことをお勧めしますか? – einpoklum

関連する問題