Domanda

Forse ancora migliore è: Perché lo standard richiede l'inoltro a una classe di base in queste situazioni? (Yeah yeah yeah - Perché? -. A causa)

class B1 {
public:
    virtual void f()=0;
};
class B2 {
public:
    virtual void f(){}
};
class D : public B1,public B2{
};
class D2 : public B1,public B2{
public:
    using B2::f;
};
class D3 : public B1,public B2{
public:
    void f(){
        B2::f();
    }
};
D d;
D2 d2;
D3 d3;

MS dà:

sourceFile.cpp
sourceFile.cpp(24) : error C2259: 'D' : cannot instantiate abstract class
        due to following members:
        'void B1::f(void)' : is abstract
        sourceFile.cpp(6) : see declaration of 'B1::f'
sourceFile.cpp(25) : error C2259: 'D2' : cannot instantiate abstract class
        due to following members:
        'void B1::f(void)' : is abstract
        sourceFile.cpp(6) : see declaration of 'B

e allo stesso modo per il compilatore MS.

I potrebbe acquistare il primo caso, D. Ma in D2 - f è senza ambiguità definita con la dichiarazione utilizzando, perché è che non basta per il compilatore per essere richiesto di compilare il vtable?

Dove nello standard viene definito questa situazione?

aggiunto reponse alla risposta

Per quanto riguarda la risposta qui sotto che ho accettato:

Perché questo non sembra un errore nelle specifiche? - Se uno ha una gerarchia di ereditarietà con una serie di f non virtuale () 's, il cui uso nelle classi derivate essendo determinata utilizzando istruzioni, e che si cambia decl di f in una classe di base virtuale allora che può cambiare che f è chiamato nelle classi derivate con utilizzando le istruzioni per scegliere il loro f. Si tratta di una c ++ "Beccato" di cui ero a conoscenza. Essa può essere parte del linguaggio, ma "azione a distanza" come mi mette a disagio e mi sembra una violazione di una sorta di principio di correttezza / manutenzione (che non riesco a formulare in questo momento).

Ma posso dare un esempio:

#include <iostream>
using std::cout;


namespace NonVirtual_f{

class C0 {
public:
    void f(){cout<<"C0::f()"<<'\n';}
};

class C1 : public C0{
public:
    void f(){cout<<"C1::f()"<<'\n';}
};

class C2 : public virtual C1{
public:
    void f(){cout<<"C2::f()"<<'\n';}
};

class D3 : public virtual C1, public C2{
public:
    using C1::f;
};


}//namespace NonVirtual_f

namespace Virtual_f{


class C0 {
public:
    virtual void f(){cout<<"C0::f()"<<'\n';}
};

class C1 : public C0{
public:
    void f(){cout<<"C1::f()"<<'\n';}
};

class C2 : public virtual C1{
public:
    void f(){cout<<"C2::f()"<<'\n';}
};

class D3 : public virtual C1, public C2{
public:
    using C1::f;
};



}//namespace Virtual_f




int main(int argc,const char* const*argv){

    NonVirtual_f::D3 nv3;
    nv3.f();

    Virtual_f::D3 v3;
    v3.f();

    return 0;    
} 

Da cui l'output:

C1::f()
C2::f()

Tutto ciò che è cambiato è la virtualità di f in C0. In particolare, una volta che la non virtualità di f in una classe base è scelto, non può essere modificato senza problemi di manutenzione, se una classe derivata (che in generale si non possono Know circa) ha "override" come nell'esempio immediatamente sopra.

Se si contatore con "Be ', non ignorare in questo modo, nel caso non virtuale", sono d'accordo che è una cattiva pratica, ma questo sembra più di questo. Per me la lingua dovrebbe:

proibisce l'utilizzo in non virtuale :: D3 (non è possibile attualmente in quanto vi possono essere altri sovraccarico di f per portare in [a meno di utilizzare consentito una firma nel caso function])

o

respingere usando dichiarazioni di funzioni completamente e l'inoltro vigore

o

avere utilizzando effettivamente sostituire in tutti i casi

o

permettere qualche dichiarativa sintattica per funzioni (essenzialmente una funzione utilizzando) come:

void f(*signature*) = C2::f;

Che cosa, esattamente, mi manca qui? qualcuno può venire con uno scenario che chiarisce il "perché" di questa scelta nella norma?

È stato utile?

Soluzione

Lo standard C ++ dice nel §10.3 / 2:

  

Le regole di ricerca utente (10.2) vengono utilizzati per determinare l'overrider finale per una funzione virtuale nell'ambito di una classe derivata ma nomi ignorando introdotte dalla usando-dichiarazioni .

Quindi, anche se si utilizza using B2::f; di portare B2::f() nella classe derivata, non è considerato di override B1::f().

Quindi, D2 è astratta a causa del §10.4 / 4:

  

Una classe è astratta se contiene o eredita almeno una funzione virtuale pura per la quale l'overrider finale è puro virtuale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top