2009-11-05 18 views
9

私はC++である場合:私はclass Bmyfunction定義からvirtualを削除した場合、それは私がclass Cclass Bに基づいていた場合、私はそれ以来、myfunctionをオーバーライドすることができなかったということを意味して次にC++仮想関数の実装?

class A { 
    private: virtual int myfunction(void) {return 1;} 
} 

class B: public A { 
    private: virtual int myfunction(void) {return 2;} 
} 

静的にコンパイルされますか?

また、私はあなたが一般公開されたときに何が起こるか混乱しています。 class Bmyfunctionの定義を公開するように変更した場合(これはclass Aのものが非公開のままです)、これは私がしてはならない重大なエラーですか?仮想関数は同じ型を保持する必要があるので違法だと思うが、それが間違っているかどうかを教えてください。

ありがとうございます!

+5

派生クラスのメソッドに "virtual"キーワードを明示的に記述する必要はありません。あなたはそれを省略することができますが、それを持つのは良いスタイルです。 – varnie

答えて

15

「仮想」の最初の定義は重要なものです。その基底からの関数は、派生したときから仮想になります。つまり、再実装された仮想関数呼び出しに「仮想」は必要ありません。基本クラスの関数シグニチャーが仮想クラスではなく、派生クラス内で仮想クラスである場合、基本クラスは多態的な振る舞いを持ちません。

class Base 
{ 
    public: 
    void func(void){ printf("foo\n"); } 
}; 
class Derived1 : public Base 
{ 
    public: 
    virtual void func(){ printf("bar\n"); } 
}; 
class Derived2 : public Derived1 
{ 
    public: 
    /* reimplement func(), no need for 'virtual' keyword 
     because Derived1::func is already virtual */ 
    void func(){ printf("baz\n"); } 
}; 

int main() 
{ 
    Base* b = new Derived1; 
    Derived1* d = new Derived2; 

    b->func(); //prints foo - not polymorphic 
    d->func(); //prints baz - polymorphic 
} 
+0

ありがとう、とても助かりました! – ash

+0

ようこそ。また、 "Base * b"は実際にはDerived1であると付け加えるべきです。必要な状況で安全なダウンキャストを実行するには、dynamic_castを使用します。 –

+0

しかし、著者の例はプライベートメンバーをカバーしています。 – bua

1

あなたはクラスBにmyfunction定義からvirtualを削除する場合は、

コンパイラはあなたのためにこれを追加します。多型のV-Tableを記入する。

!! BUT !! (クラスB:公共A)

あなただけのパブリッククラスAのメンバーにアクセスする必要があります

定義:

class B: private A 
{ 

} 

が原因とするクラスAのすべて(でもパブリック)メンバー、ということクラスBのプライベートになる。 シンプル化あなたはパブリックメンバーにアクセスすることはできません。

class A 
{ 
    private: 
     friend class B; 
} 

さらにお得情報HEREを:あなたは、いくつかの友人を宣言することができます回避策

+0

クイック返信ありがとう! – ash

+0

答えは少し混乱しています。答えから、クラスBはクラスAから継承したパブリックメンバーにアクセスすることはできませんが、それはAのBフレンドを宣言することによって解決されます。私はそれが正しいとは思いません。 BはAから公開メンバーと保護されたメンバーにアクセスできますが、BのユーザーはAの公開メンバーにアクセスできず、これは友人宣言によって解決されません。何かが間違っていると思いますか? – stefaanv

+0

はい、私の例の私的継承が欠落しています。 – bua

7

関数が基本クラスで仮想化されると、それは他のすべてのサブクラスに対して仮想になります。

public、protectedおよびprivateは、関数の仮想的性質には影響しません。

+0

ありがとうございます!表示情報をありがとう。 – ash

+0

仮想関数を保護または非公開にすることで、サブクラスでそれらを呼び出す必要がある場合、クラスのユーザーにヒントを与えることができます。 http://www.gotw.ca/publications/mill18.htm –

0

virtualの挙動は、それはあなたがサブタイプのオブジェクトを指す1型のポインタを持っているときに呼び出されるメソッド影響ということです。たとえば:

B* obj = new B; 
A* base = obj; 

何がobj->myfunction()を呼び出したときに起こることはAは仮想であることをmyfunctionを宣言するかどうかに依存します。仮想でない場合は、A型のポインタがあるので、Aで定義された関数を呼び出し、結果は1です。ただし、Amyfunctionを仮想と定義している場合は、ポインタのタイプではなく実際のオブジェクトのタイプに基づいて実行時にルックアップが実行されます。オブジェクトは実際にはBなので、Bで定義されている実装が使用され、結果は2です。

さらに詳しい情報はthe C++ FAQ Lite section on virtual functionsにあります。