2016-03-27 3 views
9

Diciamo che ho una classeQual è la differenza tra non implementare ed eliminare operatori comuni?

class Object 
{ 
public: 
    Object(int i) : num(i) {}; 

    int getNum() const { return num; } 
private: 
    int num; 
}; 

Ora, se provo a fare questo

Object obj{ 1 }; 
Object obj2{ 2 }; 
Object obj3 = obj + obj2; //This is wrong 

Questo è illegale: 'Object' does not define this operator or a conversion to a type acceptable to the predefined operator.

L'aggiunta di Object operator+(const Object&) = delete; non modifica nulla, ad eccezione del messaggio di errore: 'Object Object::operator +(const Object &)': attempting to reference a deleted function.

Il delete è necessario solo per gli operatori che hanno una dichiarazione implicita (come l'operatore di assegnazione e il costruttore di copia/spostamento) o cambia qualcos'altro nel mio caso?

+0

Penso che il motivo principale è stato aggiunto alla lingua è stata per prevenire la copia o lo spostamento in modo esplicito. – karakfa

+0

Questo è quello che ho pensato anch'io, ma se è permesso ci deve essere una ragione. – Rakete1111

risposta

8

L'eliminazione è necessaria solo per gli operatori che hanno una dichiarazione implicita (come l'operatore di assegnazione e il costruttore di copia/spostamento) o cambia qualcos'altro nel mio caso?

No e no. Il tuo caso è semplicemente troppo semplice perché una differenza del genere sia importante.

= delete serve a due scopi:

1: Si rimuove forzatamente funzioni che (potenzialmente) altrimenti lì. Vale a dire, le funzioni membro speciale.

2: specifica che una funzione con quella firma non può essere chiamata. Questa è essenzialmente una generalizzazione del # 1.

L'esempio archetipo di quest'ultimo è per impedire la conversione implicita di argomenti di funzione. Se si esegue questa operazione:

void foo(float val); 
void foo(int) = delete; 

Non è più possibile chiamare foo(5); è necessario utilizzare foo(5.f). Perché? Poiché il compilatore vedrà il secondo sovraccarico, verificherà che corrisponda al meglio alla chiamata, quindi immediatamente non riesce perché la funzione viene eliminata.

volte questo è fatto in questo modo, così:

void foo(float val); 
template<typename T> void foo(T&&) = delete; 

Questo garantisce che è possibile solo chiamarlo con un vero e proprio float. Nessun tipo implicitamente convertibile da float funzionerà.

+0

Perché il riferimento di rvalue è necessario per il modello, nell'ultimo caso? Sembrerebbe che solo un semplice "modello void foo (T) = delete" sia sufficiente a tale scopo. –

+0

@SamVarshavchik: Probabilmente non è necessario. –

+0

@SamVarshavchik Consideriamo, ad esempio, 'void g (AbstractClassWithConversionToFloat & x) {pippo (x); } '. 'void foo (T) = delete;' avrebbe un errore di sostituzione (perché i tipi di parametri di funzione non possono essere astratti) e non riesce correttamente a bloccare la chiamata. –

1

L'anwer di @NicolBolas è perfettamente accettabile. Ecco un altro esempio per illustrare che a volte non è sufficiente non dichiarare/definire una funzione perché qualcun altro lo fa (come il compilatore ha generato funzioni membro speciali) e il tuo codice può chiamarlo (ad esempio tramite costruttori impliciti o operatori di conversione).

#include <iostream> 

// your code 
struct Base {}; 

// some teammate 
struct Wrap 
{ 
    /* implicit */ Wrap(Base const& b) {} 
}; 

void fun(Wrap const&) { std::cout << __PRETTY_FUNCTION__ << '\n'; } 

// client code 
int main() 
{ 
    Base b; 
    fun(b); // oops, probably didn't intend to call fun(Wrap const&) 
} 

Live Example che emette void fun(const Wrap &).

Ora ai vecchi tempi pre-C++ 11, si poteva dichiarare ma non definire

void fun(Base const&); // no definition provided 

Live Example che emette l'errore linker

da C++ 11 in poi, è possibile eliminare esplicitamente la stessa funzione

void fun(Base const&) = delete; // C++11 onwards 

Live Example che emette l'errore del compilatore (che è molto più informativo rispetto al precedente errore di linker)

main.cpp:20:5: error: call to deleted function 'fun' 
    fun(b); // oops, probably didn't intend to call fun(Wrap const&) 
    ^~~ 
main.cpp:6:6: note: candidate function has been explicitly deleted 
void fun(Base const&) = delete; // C++11 onwards 
    ^
Problemi correlati