2015-08-18 13 views
6

Sto studiando la conversione di costruttori e operatori di conversione in C++. Quello che ho imparato finora è che qualsiasi costruttore non esplicito che prende solo un parametro (e qualsiasi numero di argomenti facoltativi di default) rappresenta una conversione di tipo di classe implicita a quel tipo di classe, per esempio se una classe definisce un costruttore che ha un parametro di tipo int posso usare un int ovunque sia necessario un oggetto di tale tipo di classe:conversioni implicite da e verso tipi di classe

(supponendo class_type ha un sovraccarico + = operatore)

class_type a; 
a+=5; 

in questo caso 5 è convertito implicitamente (tramite il costruttore di conversione) a class_type e viene chiamato l'operatore sovraccarico.

momento, (almeno per me) parte difficile: so di poter definire un operatore di conversione come una funzione membro:

operator int() {....}; 

che converte l'oggetto della class_type al int tipo primitivo, e può usare che la conversione del tipo:

class_type a; 
a+5; 

in questo caso ho letto che l'oggetto viene convertito in un int attraverso il suo operatore di conversione e quindi l'operatore somma Buil-in si chiama. Ma cosa succede se ho definito un operatore sovraccarico + per prendere due oggetti class_type come argomenti? qualcosa come

class_type operator+(const class_type&,const class_type &c);

come si suppone che il compilatore di sapere quale chiamare con funzione di corrispondenza? la conversione in int si verifica solo implicitamente quando viene definito solo l'operatore integrato?

grazie!

edit:

in realtà, ho cercato di scrivere del codice per provare in modo efficace fuori, si è scoperto che il mio compilatore (g ++) non emette alcun errore chiamata ambigua!

questo è l'intestazione della classe (insieme con l'operatore non memeber + dichiarazione di funzione):

#include <iostream> 

class wrapper { 
    friend std::ostream &operator<<(std::ostream&,const wrapper&); 
    public: 
    wrapper()=default; 
    wrapper(int); 
    int get(); 
    operator int() const; 
    wrapper operator+(int); 
    private: 
    int a=10; 
}; 

std::ostream &operator<<(std::ostream&,const wrapper&); 

e questo è il codice principale:

#include "wrapper.h" 

int main() 
{ 
    using namespace std; 
    wrapper w1; 
    wrapper w2(5); 
    cout<<w1<<" "<<w2<<endl; 
    w1+1; 
} 

ora, ho definito una conversione costruttore da int a wrapper E un operatore di conversione da tipo di classe a int (Ho anche sovraccaricato l'operatore di output < < per stampare alcuni risultati), ma quando il il compilatore valuta l'espressione w1+1 sembra a posto. Come potrebbe essere ??

+1

Forse leggere [questo riferimento implicito di conversioni] (http://en.cppreference.com/w/cpp/language/implicit_cast) potrebbe essere d'aiuto? –

+0

Inoltre, per l'esempio 'a + = 5' presumo tu intenda che hai sovraccaricato' operator + = 'prendendo' class_type' come argomento? Perché potrebbe facilmente essere stato un sovraccarico prendendo un 'int'. –

+2

Come regola generale, avere sia costruttori impliciti che operatori di conversione impliciti confonde non solo il compilatore ma anche i lettori umani. –

risposta

11

Se si dispone ad esempio della seguente dichiarazione di classe che contiene un costruttore di conversioni e un operatore di conversione

struct A 
{ 
    A(int x) : x(x) {} 
    operator int() const { return x; } 
    int x; 
};   

const A operator +(const A &a1, const A &a2) 
{ 
    return A(a1.x + a2.x); 
} 

THEN

a1 + a2; 

dove A1 e A2 sono dichiarate come per esempio

A a1(10); 
A a2(20); 

sarà ben formato, perché non c'è bisogno di chiamare una funzione di conversione. Entrambi gli operandi corrispondono alle dichiarazioni dei parametri dell'operatore +.

Tuttavia, se si scrive per esempio

a1 + 20; 

quando il compilatore genera un errore perché non v'è un'ambiguità. Il compilatore può applicare il costruttore di conversioni A(int) per convertire il secondo operando in tipo A e chiamare l'operatore definito per gli oggetti di tipo A. Oppure può applicare l'operatore di conversione operator int per convertire il primo operando in tipo int e chiamare l'operator + integrato per gli oggetti di tipo int.

Per evitare questa ambiguità, è possibile dichiarare il costruttore o l'operatore (o entrambi) con l'identificatore di funzione explicit.

Ad esempio

explicit A(int x) : x(x) {} 

o

explicit operator int() const { return x; } 

In questo caso solo una conversione implicita esisterebbe e non c'era un ambigiuty.

Vorrei aggiungere la descrizione precedente che a volte alcuni operatori di conversione possono essere chiamati implicitamente anche se sono dichiarati con l'identificatore di funzione explicit.

Per esempio Secondo l'++ standard C (dichiarazioni 6.4 Selezione)

  1. ...The value of a condition that is an expression is the value of the expression, contextually converted to bool for statements other than switch;

e (5.16 condizionale operatore)

1 Conditional expressions group right-to-left. The first expression is contextually converted to bool (Clause 4).

Così, per esempio se la classe di cui sopra è il seguente operatore di conversione dichiarato con la funzione specificatore explicit

explicit operator bool() const { return x != 0; } 

Tuttavia sarà chiamato implicitamente per esempio nella seguente dichiarazione

A a(10); 

std::cout << (a ? "true" : "false") << std::endl; 

Qui una sarà convertito a un oggetto di tipo bool nell'operatore condizionale.

EDIT: Dopo aver aggiornato il tuo domanda a questo espressione

w1+1; 

è una corrispondenza esatta per l'operatore

wrapper operator+(int); 

Né la conversione sono obbligatori. Quindi il codice viene compilato correttamente.

+0

Suvviato per ricordare il caso speciale in cui l''operatore esplicito bool' viene chiamato implicitamente o [convertito contestualmente] (http://stackoverflow.com/a/6242355/183120) come lo chiama lo standard. – legends2k

+0

@ legends2k Sei una persona gentile !: Potresti anche revocare le mie altre risposte? :) –

+0

@VladfromMoscow, per favore puoi dare un'occhiata alle mie modifiche? molte grazie! – Luca

3

questo è qualcosa che si può facilmente provare e vedere cosa fa il compilatore:

#include <iostream> 

struct ABC { 
    int v; 
    ABC(int x) : v(x) { } 
    operator int() const { return v; } 
    void operator +=(ABC const &that) { 
     v += that.v; 
    } 
}; 

ABC operator+(ABC const &lhs, ABC const &rhs) { 
    return { lhs.v + rhs.v }; 
} 

int main() { 
    ABC a(5); 
    std::cout << a + 1 << '\n'; 
    a += 10; 
    std::cout << a << '\n'; 
} 

what if I defined an overloaded + operator to take two class_type objects as its arguments?

GCC

error: ambiguous overload for 'operator+' (operand types are 'ABC' and 'int')

Il compilatore vede due candidati: operator+(int, int) <built-in> e ABC operator+(const ABC&, const ABC&). Ciò significa che potrebbe implicitamente convertire non solo lo 5 in a + 5 in a ma anche lo a in int. Pubblica queste conversioni Entrambe le funzioni operator+ diventano potenziali corrispondenze.

How is the compiler supposed to know which one to call through function matching?

Non sa quindi l'errore.

does the conversion to int only happens implicitly when only the built-in operator is defined?

Sì, altrimenti non converte automaticamente class_type a int. Tuttavia, int a class_type accadrebbe implicitamente a meno che non si fanno costruttore explicitclass_type s':

explicit ABC(int x) : v(x) { } 

Se l'accesso hai per C++ 11, allora anche voi fate la funzione di conversione esplicita:

explicit operator int() const { return v; } 
Problemi correlati