5

次のスニペット コードを見ました。

class Foo
{
public:
        void virtual func() throw (int, float) = 0;
};

class Bar : public Foo
{
public:
        void virtual func() throw(short);      // line 1: compile error "
                                                                      // looser throw specifier"
        void virtual func() throw();                // line 2: can compile
        void virtual func() throw(float, int); // line 3: can compile
        void virtual func() throw(float);        // line 4: can compile
        void virtual func() throw(int);           // line 5: can compile

};

int main(void)
{
        return 1;
}

Q1> とはどういう意味ですか?

void virtual func() throw (int, float) = 0;

Q2>なぜline1はコンパイラを通過できないのですか?

ありがとうございました

4

5 に答える 5

9

これを分解しましょう。宣言:

void virtual func() throw (int, float) = 0;

あなたが質問している2つの構成があります。構文は、=0宣言された関数が'abstract'であることをコンパイラーに通知します。これは、関数をで定義する必要がないことclass Foo(ただし、通常は定義できません)、およびのオブジェクトをclass Foo直接作成できないことをコンパイラーに通知します。ローカル、グローバル、または経由のいずれかとしてnew。ただし、のオブジェクトへのポインタまたは参照を持つことができますclass Foo。一部の派生クラスは、非抽象関数として関数をオーバーライドする必要があります。そのクラスのオブジェクトは直接作成できます(「具体的」にされていない他の抽象関数がない限り)。

構成はthrow (int, float)例外仕様です。これは、関数のコントラクトが、型の例外のみをスローするか、例外をスローするintfloatどうかをコンパイラーに通知します。関数が他の種類の例外をスローした場合、コンパイラはそれを特別に処理する必要があります(を呼び出すことによってstd::unexpected())。

ここで、派生クラスでその関数を次の宣言でオーバーライドしようとすると、次のようになります。

void virtual func() throw(short);

関数のコントラクトは、例外がスローされた場合にタイプの例外をスローすることであると言っていますshort。ただし、スローshortはオーバーライドされる関数のコントラクトの一部ではないため、コンパイラーはそれを許可しません。

このようにオーバーライドを宣言する場合:

void virtual func() throw(float);

floatオーバーライドは、元の宣言のコントラクトの一部であるをスローできると言っています(コントラクトをint破らないものをスローしない場合、元のコントラクトは、関数がスローすることを許可されているとだけ言っていますがint、それがしなければならないこと)。

標準の関連部分は15.4/3例外仕様です。

仮想関数に例外仕様がある場合、派生クラスのその仮想関数をオーバーライドする関数の定義を含むすべての宣言は、基本クラスの仮想関数の例外仕様によって許可される例外のみを許可するものとします。

標準では、例外仕様は関数の型(15.4 / 12)の一部ではないと明示的に規定されているため、関数ポインターは、たとえば、異なる例外仕様を持つ関数を指すことができます。

于 2010-09-21T19:24:27.077 に答える
6

同じ関数シグネチャを何度も定義しています。関数のあいまいさを解消するには、さまざまなthrow()修飾子だけでは不十分です。

throw()修飾子は単に、指定された関数が修飾子の後の括弧内にリストされた型のみをスローすることが期待されることを意味します。ただし、これによって実際に関数がスローされるのを防ぐことはできません。むしろ、関数が実際にリストされていない型をスローした場合、プログラムは終了します。

于 2010-09-21T18:54:46.493 に答える
3

基本クラスで定義している関数は、保証を行っています。それは、intまたはのみをスローできfloatます。short上記のいずれでもないをスローすると言って保証を破っているため、1行目は失敗しています。

Q1の= 0は、インスタンスを作成しようとする各派生クラスが、この関数の独自の宣言と実装を提供する必要があることを宣言しています。基本クラスも実装を提供する場合がありますが、通常は提供しません。

于 2010-09-21T18:56:50.337 に答える
2

名前付き throw ステートメントの意味は、関数がそれらの名前付き例外のみを直接的または間接的にスローできることを宣言することです。

だから行:

void virtual func() throw(int, float) =0;

つまり、この基本型を継承するクラスは、int または float のいずれかのみをスローできます。他のタイプの例外またはオブジェクトを直接的または間接的にスローすることはできません。存在する場合は、unexcepted()関数が呼び出されます。デフォルトでは、これはterminate()関数を呼び出します。関数を使用してそれをリセットすることはできますset_unexpectedが、それでも.

これらの throw ステートメントをインターフェイスに追加することを選択すると、実際に自分自身を制限することになります。

于 2010-09-21T18:56:00.277 に答える
2

関数をオーバーライドする場合、virtual指定する例外指定子は、オーバーライドする関数で指定したものと少なくとも同じくらい制限的でなければなりません。これにより、基本クラスの例外仕様が違反されるのを防ぎます。

基本クラスの例外指定子 [ throw (int, float)] は a のスローを許可しないためshort、派生クラスは a のshortスローを許可できません。せいぜい、intおよび/またはfloat;を許可する場合があります。これらの可能性のいずれかが基本クラス関数の例外仕様よりも制限的であるため、いずれかのみがスローされるか、どちらもスローされない可能性があります。

于 2010-09-21T18:58:17.783 に答える