2015-09-21 8 views
5

私は、Visual Studioでは0の警告が生成されるため、基本オブジェクトからのパブリック関数をプライベート関数にオーバーライドすることはC++で許可されていることが分かりました。それを行う潜在的な危険はありますか?私的な機能を一般に上書きする潜在的な危険性は何ですか?

もし存在しなければ、基底オブジェクトの仮想関数をprivate、protected、publicで宣言することとの違いは何ですか?

+2

Javaの 'private'メソッドをオーバーライドすることはできません。私はあなたの質問でそれの言及を削除しました。 –

+0

多面的に誰かがそれを使用すると、たとえそれが派生クラスで公開されていてもプライベート関数を呼び出すことはできません... btw、これは私には意味がありません。 – Melkon

+1

@Rahn 'C++では、Visual Studioは0警告を生成するので、基底オブジェクトからの公開オブジェクトへのプライベート関数のオーバーライドは許可されています.'このような前提を慎重にしてください。 0という警告が出されても、C++で許可されているわけではありません。つまり、Visual Studioでは許可されています。それでも警告レベルが上がった場合は警告が表示されることがあります(わかりません)。とにかく、たとえあるコンパイラがうまくいても、別のコンパイラがあるとは限りません。 C++標準がここでは本当の権威です。 – Steve

答えて

1

これを実行する危険性はありますか?

あなたはまだ非常に限られているので、私は、そうは思わない:

class Base 
{ 
private: 
    virtual void foo(){} 
}; 

class Derived1 : public Base 
{ 
public: 
    virtual void foo(){ Base::foo(); } 
}; 

class Derived2 : public Base 
{ 
public: 
    virtual void foo(){} 
}; 

int main() 
{ 
    Derived1 d1; 
    d1.foo(); //error 
    Base * d2 = new Derived2(); 
    d2->foo(); //error 
} 

をだから、最高の状態であなたはそれから関数を呼び出していない場合(オーバーロードされた関数を呼び出すことができるようになりますベースクラスの機能はそのままですが、基本クラスの機能は同じ可視性を持ち、アクセスできなくなります。

+3

'virtual void foo(){Base :: foo(); } '待って...これは実際にコンパイルされますか?子クラスは 'Base :: foo()'にアクセスできないので、 'main()'だけでなく、エラーがあるはずです... – anderas

+0

もちろん、エラーはその行も指していますメインのものとして、それがポイントです。申し訳ありませんが私は十分に明確にしていない場合。 – SingerOfTheFall

0

派生クラスでオーバーライドすることによって、アクセスの可視性を変更する場合は、基本クラスの可視性が変更されません:

をそうで:

class Base { 
public: 
    virtual ~Base() = default; 
protected: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
public: 
    void foo() override {}; 
}; 

その後

Derived d; 
Base& b = d; 

d.foo(); // valid 
b.foo(); // invalid 
0

「がそこにISN場合基本オブジェクトのプライベート、保護、パブリックで仮想関数を宣言することの違いは何ですか?

機能にアクセスする方法によって異なります。使用するオブジェクト/ポインターのタイプによって、関数にアクセスできるかどうかが決まります。

class Base 
{ 
    public: 

     virtual void foo() {} 
}; 

class Derived : public Base 
{ 
    private: 

     virtual void foo() {} 
}; 

int main() 
{ 
    Derived* dptr = new Derived; 
    Base* bptr = dptr; 

    dptr->foo(); // Can't use it. Derived::foo is private 
    bptr->foo(); // Can use it. Base::foo is public. 
} 

g ++ 4.9.3を使用したコンパイラメッセージ。

socc.cc: In function ‘int main()’: 
socc.cc:12:20: error: ‘virtual void Derived::foo()’ is private 
     virtual void foo() {} 
        ^
socc.cc:20:14: error: within this context 
    dptr->foo(); // Can't use it. Derived::foo is private 
2

ベースオブジェクトでは、民間の保護と公共 で仮想関数を宣言するとの違いは何ですか?

違いは、private仮想関数は基本クラスからのみ呼び出すことができるということです。これは、関数が外部クラスインタフェースの一部でなく、基本クラスのみで使用される場合に便利です。そのため、ユーザーは(その他の)基本クラスのメンバーを呼び出し、そのメンバーは仮想関数を呼び出します。例えば:彼らは仮想であるという事実は、クラスの内部およびそのサブクラスであるため、

class Base { 
    virtual void stage1()=0; // derived classes override this 
    virtual void stage2()=0; 
    public: 
    void run() { stage1(); stage2(); } // users call this 
}; 

はまた、あなたがpublicで、すべての仮想関数を作るべきではないという観点では、そこにある、とユーザーはそれを認識すべきではありません。同じ関数を外部コードからオーバーライドして呼び出し可能にする必要はほとんどありません。これにより、基本クラスはどの(仮想)関数をどの(非仮想)パブリックメソッドから呼び出すことができるかを制御することができ、より簡単な操作が可能になります。

this article by Herb Sutterで詳細を参照してください:

...各[パブリック]仮想 関数は2つのジョブをやっている:それは 公共のだからそれはインターフェースを指定するです...。実装の詳細は つまり内部的にカスタマイズ可能なビヘイビアを指定しています...パブリック仮想の 関数は本質的に2つの大きく異なるジョブを持っています。 というのはよく分からないということで、 は別のアプローチと考えるべきです。 インターフェイスの仕様を実装のカスタマイズ可能な仕様 の動作と区別したい場合はどうすればよいですか?

...要するに

は、基底クラスの仮想関数は、プライベート(またはあなたが本当に必要がある場合は、保護 )を作ることを好みます。これにより、インターフェイスが安定化し、 の実装の決定がより簡単に変更され、後でリファクタリングされるように、 インターフェイスと実装の懸念が分かります。

しかし、私は

0

仮想関数は、派生クラスの実装のためのカスタマイズポイントである...これは本当に広く使用されているかどうかを言う資格はないです。それがプライベートであれば、純粋に実装の詳細です。派生クラスでよりアクセシブルにすると、インプリメンテーションの詳細がすべて表示されます。特に、クライアントコードは、実装を簡単に変更することができないようにその詳細に依存するようになります。クライアントが本来意図しているインタフェースよりも誤った方法で呼び出すほうが簡単で、特定のコンテキストでのみ有効な結果が得られ、元のインタフェースよりも脆弱になります。

関連する問題