web-dev-qa-db-ja.com

C ++はプライベートとして純粋な仮想メソッドをパブリックとしてオーバーライドします

なぜこれが起こるのですか?

http://coliru.stacked-crooked.com/a/e1376beff0c157a1

class Base{
private:
    virtual void do_run() = 0;
public:
    void run(){
        do_run();
    }
};

class A : public Base {
public:
    // uplift ??
    virtual void do_run() override {}
};


int main()
{
    A a;
    a.do_run();
}

[〜#〜] private [〜#〜]仮想メソッドをパブリックとしてオーバーライドできるのはなぜですか?

16
tower120

https://en.cppreference.com/w/cpp/language/virtual#In_detail によると、ベースのvirtualメンバー関数をオーバーライドすると、関数名、パラメーター、const/volatile-nessおよびref修飾子。戻り値の型やアクセス修飾子など、気になると思われるものは気にしません。

リンクされたリファレンスは、特に次のようにも述べています。

Base :: vfをオーバーライドするために表示する必要はありません(プライベートとして宣言するか、プライベート継承を使用して継承できます)。

私が明示的に見つけることができるものはこれを行う許可を与えていませんが、オーバーライドのルールはそれを妨げません。 virtual関数および既存の関数をオーバーライドする関数によって許可されており、このケースを禁止していません。

なぜこれが言語であるかを尋ねている場合、標準化委員会に尋ねる必要があるかもしれません。

17

その動作は意図されています。メソッドが仮想の場合、アクセス修飾子に関係なく、派生クラスでカスタマイズできることを意味します。

こちら を参照

11
rawberry

プライベート仮想メソッドをパブリックとしてオーバーライドできるのはなぜですか?

あなたが間違った角度で基本メソッドがプライベートであることを見るからです。 _B::do_run_プライベートであることは、「このクラスのメンバーと友達だけが使用できる」という意味です。派生クラスによるオーバーライドを禁止するには、個別の指定子が必要ですが、virtualではなく単純に指定できます。別の側のクラスAを使用すると、誰でもA::do_run()を呼び出すことができます。そうするかどうかは、クラスAデザイナーが決定します。ですから、あなたが見るように隆起はありません。

3
Slava

この実装は、基本クラスへのアクセス方法と構成を変更しないことに注意してください。

Base& b = a;
b.do_run();

動作しないでしょう。

Scott Meyersによる「Effective C++」でより詳細に説明されているその背後にある理論的根拠があることを覚えています。ただし、重要な実用的な機能は、そのような柔軟性を反対方向に使用できること、パブリックベースクラスメンバーを派生クラスのプライベート関数でオーバーライドして、クライアントにインターフェイスとしてベースクラスを使用させ、直接使用するように誘惑しないことです。隠された実装のままであるはずの派生物。

2
jszpilewski

目的が基本クラスのプライベートコードを記述し、それをオーバーライドする可能性を防ぐことである場合は、基本クラスにプライベート関数を実装し、finalと宣言します。それ以外の場合:誰かがプライベート仮想を使用する必要がある場合? ISOCPP.ORG FAQ

0
Amit G.