2012-08-15 7 views
8

私はC + +のクイズを行っています。そして、次のコードを見つけました。違法ですが、理由を理解できません。なぜこの行が説明できますか:継承 - なぜこれは違法ですか?

Box* b1 = s1->duplicate(); 

は、「Shape *からBoxに変換できません」というコンパイラエラーを生成しますか? s1->duplicate()は、s1が実際にBoxを指しているので、Box::duplicate()を呼び出していると思っていましたが、コンパイラエラーからはShape::duplicate()のように見えます。

#include <iostream> 

struct Shape 
{ 
    virtual Shape* duplicate() 
    { 
    return new Shape; 
    } 

    virtual ~Shape() {} 
}; 

struct Box : public Shape 
{ 
    virtual Box* duplicate() 
    { 
    return new Box; 
    } 

}; 

int main(int argc, char** argv) 
{ 
    Shape* s1 = new Box; 

    Box* b1 = s1->duplicate(); 

    delete s1; 
    delete b1; 
    return 0; 
} 
+1

[Tのため彼の](http://stackoverflow.com/questions/4665117/c-virtual-function-return-type)。 –

答えて

8

Shape::duplicates()Shape*を返します。これはBox*ではありません。実際に返す実行時の型は、それとは関係ありません。どのようにしてShape*が返され、実際にBoxを指しているかコンパイラが知ることができましたか?

編集:このことについて考える:

struct Shape 
{ 
    virtual Shape* duplicate() 
    { 
    return new Shape; 
    } 

    virtual ~Shape() {} 
}; 

struct Box : public Shape 
{ 
    virtual Box* duplicate() 
    { 
    return new Box; 
    } 

}; 

struct Sphere : public Shape 
{ 
    virtual Sphere* duplicate() 
    { 
    return new Sphere; 
    } 

}; 

Shape* giveMeABoxOrASpehere() 
{ 
    if (rand() % 2) 
     return new Box; 
    else 
     return new Sphere; 
} 

// 
Shape* shape = giveMeABoxOrASphere(); 
// What does shape->duplicate() return? 

Box* shape = giveMeABoxOrASphere(); 
// shoud this compile? 
+0

Hmm。まあ、私は、コンパイラが 'Shape * s' = new Box'を受け入れることができれば、' s1'がBoxへのポインタになっていることを何らかの形で知っているということを考えていたと思います。遅いです、私の脳は揚げられていると思います。 。 。 – BeeBand

+2

@BeeBand: 'Shape * s = new Box;'と 'Box * b = new Shape; 'の間には重要な違いがあります。 – aschepler

+1

@BeeBandこの場合、 'dynamic_cast'で調べることができるので、タイプ情報は完全に失われません。それはコンパイラが利用できないだけです。 –

15

C++言語は静的に型指定されています。あなたの呼び出しの合法性に関する決定は、コンパイル時に行われます。コンパイラは、明らかにs1->duplicate()Boxオブジェクトへのポインタを返すことを知ることができません。このような状況では、あなたのコードを受け入れることを期待するのは非論理的です。

はい、s1->duplicate()実際にはあなたの例ではBox::duplicateが呼び出されますが、コンパイラがこれをどのように認識すると思いますか?あなたの具体例からは「明白」であると言うことができますが、この言語機能の仕様はそのような「明白な」ケースを例外にしません。

1

Shape* s1 = new Box; 
Box* b1 = s1; 

がコンパイルされませんまったく同じ理由。コンパイラは、s1Boxを指しているかどうか気にする必要はありません。

あなたはs1Boxを参照することがわかっている場合は、単にそれを言う:

Box *s1 = new Box; 

構文に関する注意:Box * s1;のための解析規則は、(非常に単純化された)次のとおりである:

declaration := type-name declarator ; 
declarator := name 
      | * declarator 

解析は次のとおりです。

Box  *  s1  ; 
        ^^^^^^^^ 
        declarator 
^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ 
type-name   declarator 

あなたが1つの宣言で複数の変数を宣言すると、Box*構文は混乱することができBox* s1;より解析とより一貫性があるため、Box (* (s1))

は、それはBox *s1;を書き込むための最高のスタイルと考えられている:

Box* x, y; 

xです解析のようBoxが、yへのポインタは、Boxである:

Box (*x), y; 
+0

を知っていますか?解析する。 。 。 – BeeBand

関連する問題