C ++ annotazioni Eccezione tiro su funzioni virtuali
Domanda
ho visto il seguente frammento di codice:
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> Qual è il significato di
void virtual func() throw (int, float) = 0;
Q2> perchè linea 1 non può passare il compilatore?
Grazie
Soluzione
pausa Let questo giù. La dichiarazione:
void virtual func() throw (int, float) = 0;
ha 2 costrutti che si sta chiedendo. il costrutto =0
dice al compilatore che la funzione dichiarata è 'astratto', che dice al compilatore che la funzione non deve essere definito nel class Foo
(anche se può essere - ma di solito non lo è) e che un oggetto di class Foo
non può essere direttamente creato - sia come un locale, globale o tramite new
. Tuttavia, è possibile avere puntatori o riferimenti a oggetti di class Foo
. Alcune esigenze classe derivata per ignorare la funzione come una funzione non astratta -. Oggetti di quella classe possono essere creati direttamente (a patto che non ci sono altre funzioni astratte che non sono state fatte 'concreta')
Il costrutto throw (int, float)
è uno specifification un'eccezione. Questo dice al compilatore che il contratto della funzione è che getterà solo eccezioni di tipo int
o float
se viene generata un'eccezione. Se la funzione lancia un altro tipo di eccezione, il compilatore è obbligato a gestire questo particolare (chiamando std::unexpected()
).
Ora, se si tenta di ignorare che la funzione in una classe derivata con la seguente dichiarazione:
void virtual func() throw(short);
Stai dicendo che il contratto della funzione è che sarà generare eccezioni di tipo short
se viene generata un'eccezione. Tuttavia, gettando short
non è parte del contratto della funzione di essere sottoposto a override, in modo che il compilatore non lo consente.
Se si dichiara la sostituzione in questo modo:
void virtual func() throw(float);
Stai dicendo che l'override può gettare un float
, che fa parte del contratto della dichiarazione originale (se non si è mai genera int
che non si rompe il contratto - il contratto originale dice solo che è consentita la funzione per lanciare un int
, non che ha a).
La parte rilevante dello standard è 15,4 / 3 specifiche di eccezione:
Se una funzione virtuale ha un specifica delle eccezioni, tutti i dichiarazioni, tra cui il definizione, di qualsiasi funzione che sostituzioni tale funzione virtuale in qualsiasi classe derivata membri autorizzano eccezioni che sono autorizzati dal specifica delle eccezioni della base funzione virtuale di classe.
Si noti che la norma afferma esplicitamente che una specifica eccezione non fa parte del tipo della funzione (15.4 / 12), quindi un puntatore a funzione può, ad esempio, scegliere funzioni che hanno diverse specifiche eccezioni.
Altri suggerimenti
Si sta definendo la stessa firma funzione molte volte. Le diverse qualificazioni throw()
non sono sufficienti per disambiguare le funzioni.
Il qualificatore throw()
significa semplicemente che la funzione specificata è previsto solo per gettare le tipologie elencate tra parentesi dopo il qualificatore. Tuttavia, questo in realtà non impedisce la funzione da buttare. Piuttosto, se la funzione in realtà non gettare qualsiasi tipo non quotate, il programma terminerà.
La funzione che si sta definendo nella classe base è fare una garanzia - può lanciare solo un int
o un float
. La vostra linea 1 sta fallendo perché è rompendo la garanzia dicendo che lancerà una short
, che non è né di quanto sopra.
Il = 0
in Q1 dichiara che ogni classe derivata che si tenta di creare un'istanza di necessità volontà di fornire la propria dichiarazione e implementazione di questa funzione. La classe di base può anche fornire un'implementazione, ma in genere non è così.
Il significato delle dichiarazioni throw nome è quello di dichiarare che una funzione può lanciare solo quelli nominati eccezioni, direttamente o indirettamente.
Così la linea:
void virtual func() throw(int, float) =0;
significa che qualsiasi cosa eredita classe questo tipo di base è consentito solo a buttare sia un int o un float. Non può né gettare direttamente o indirettamente, qualsiasi altro tipo di eccezione o di un oggetto. Se lo fa, chiamerà la funzione unexcepted()
. Per impostazione predefinita, questo chiama la funzione terminate()
. Si è permesso di ripristinare che utilizza la funzione set_unexpected
ma ancora.
Con la scelta di aggiungere tali dichiarazioni tiro alla vostra interfaccia si sta limitando di te stesso.
Quando si ignora una funzione virtual
qualsiasi specificatore eccezione che fornito deve essere almeno altrettanto restrittiva come quella indicata sulla funzione che si sta prevalente. Questo impedisce la classe base di specifica eccezione venga violata.
Come la classe base eccezione identificatore [throw (int, float)
] non permette un short
ad essere gettato, la classe derivata non può consentire a un short
per essere gettato. Al massimo si può permettere un int
e / o un float
; essa può consentire solo una o né essere gettato come qualsiasi di queste possibilità sarebbe più restrittiva rispetto alla specifica eccezione della funzione classe base.