2015-04-13 5 views
10

Se compilare ed eseguire il seguente:Perché non protetto C++ - I distruttori Cli causano errori di compilazione?

using namespace System; 

ref class C1 
{ 
public: 
    C1() 
    { 
     Console::WriteLine(L"Creating C1"); 
    } 

protected: 
    ~C1() 
    { 
     Console::WriteLine(L"Destroying C1"); 
    } 
}; 

int main(array<System::String ^> ^args) 
{ 

    C1^ c1 = gcnew C1(); 
    delete c1; 

    return 0; 
} 

... il codice viene compilato senza un errore e mi corre dare questo:

Creating C1 
Destroying C1 
Press any key to continue . . . 

Se faccio lo stesso in C++ si ottiene un errore lungo le righe seguenti:

1>ProtectedDestructor.cpp(45): error C2248: 'C1::~C1' : cannot access protected member declared in class 'C1' 
1>   ProtectedDestructor.cpp(35) : compiler has generated 'C1::~C1' here 
1>   ProtectedDestructor.cpp(23) : see declaration of 'C1' 

... quindi perché è valido in CLI?

risposta

14

Questo è un problema di astrazione. C++/CLI ne ha molti, abbiamo già riscontrato il problema con la parola const. Più o meno lo stesso, il runtime non ha alcuna nozione di distruttore, solo il finalizzatore è reale. Quindi deve essere simulato. È stato piuttosto importante creare quell'illusione, il pattern RAII nel C++ nativo è sacro.

È contraffatto bloccando la nozione di un distruttore sulla parte superiore dell'interfaccia IDisposable. Quello che fa funzionare la distruzione deterministica in .NET. Molto comune, lo utilizza la parola chiave nel linguaggio C# per richiamarlo, ad esempio. Nessuna parola chiave in C++/CLI, si utilizza l'operatore delete. Proprio come faresti nel C++ nativo. E il compilatore aiuta, emettendo automaticamente le chiamate del distruttore quando si usa la semantica dello stack. Proprio come fa un compilatore C++ nativo. Salvataggio di RAII.

Astrazione decente, ma sì, perde. Il problema è che un metodo di interfaccia è sempre pubblico. E 'tecnicamente possibile per renderlo privato con implementazione dell'interfaccia esplicita, anche se è solo un ripiego:

public ref class Foo : IDisposable { 
protected: 
    //~Foo() {} 
    virtual void Dispose() = IDisposable::Dispose {} 
}; 

produce un elenco impressionante di errore quando si tenta di questo, il compilatore combatte così difficile come si può :). C2605 è l'unico rilevante: "'Dispose': questo metodo è riservato all'interno di una classe gestita". Non può mantenere l'illusione quando lo fai.

Per farla breve, l'implementazione del metodo IDisposable :: Dispose() è sempre pubblica, indipendentemente dall'accessibilità del distruttore. L'operatore delete lo richiama. Nessuna soluzione per questo.

5

Oltre alla risposta dettagliata di Hans che delete su un oggetto C++/CLI è in realtà di attivazione dell'interfaccia IDisposable, e l'interfaccia eredità è sempre pubblica , può essere fruttuoso per chiedere

Come funziona Allora viene chiamato il distruttore protetto?

I metodi Dispose generati dal compilatore chiamano il distruttore definito dall'utente. Poiché questo metodo Dispose è un membro della classe, ha accesso ai membri della classe protected e private, ad esempio il distruttore.

(Nel C++ nativo, il compilatore non è soggetto alle regole di accessibilità, poiché è quello che le impone. In .NET, il verificatore IL le applica.)


In realtà, i suoi centri spiegazione sul fatto che il compilatore non consente esplicita attuazione IDisposable::Dispose(), nel qual caso potrebbe essere un membro privato. Ma è completamente irrilevante. virtual membri possono essere raggiunti attraverso il tipo di dichiarazione. E delete non chiama object->Dispose(), chiama safe_cast<IDisposable^>(object)->Dispose().

Problemi correlati