2016-05-28 13 views
9

Io sono scomparsi alcune funzionalità importante dal std::complex come la possibilità di aggiungere un std::complex<float> e std::complex<double> o operazioni quali 1+c, cioè tra int e std::complex. La mia idea era di ricavare una nuova classe my::complex da std::complex che eredita solo tutto ciò che è già implementato e aggiunge altre cose.Esiste un buon modo per estendere una classe con operatori aggiuntivi?

Per rendere il codice compatibile con le funzioni utilizzando std::complex, ho aggiunto conversione automatica da e std::complex (e anche conversioni automatiche tra my::complex<float> e my::complex<double>).

Ora qualcosa come

my::complex<float> c1,c2,c3; 
c1 = c2 + c3; 

funziona anche se non ha attuato operator+ me stesso, dal momento che c2 e c3 sono espressi a std::complex, ha aggiunto e il risultato viene gettato di nuovo a my::complex. Suppongo che il compilatore possa ottimizzare qualsiasi copia effettiva.

Tuttavia, il seguente non funziona:

c1 = 2*(c2+c3) 

poiché std::complex non può essere moltiplicato per un numero intero (stesso problema se moltiplicare per un letto e hanno complex<float> s).

ho pensato "ok, sembra che devo aggiungere operator+ dopo tutto", ma se lo faccio, io ottenere use of overloaded operator '+' is ambiguous dal momento che il compilatore può tra std::complex e my::complex implicitamente.

C'è un modo migliore per ottenere ciò che voglio o devo completamente reimplementare tutto in std::complex e buttare via l'ereditarietà?

+1

sicuro, ma hai provato 'c1 = (c2 + c3) * 2'? – user463035818

+0

non sono sicuro, ma per aggiungere 'std :: complex ' a 'std :: complex ' Penso che non sia necessaria l'ereditarietà, ma è possibile implementare l'operatore come funzione libera – user463035818

+2

La conversione di tipo automatico è la peggiore, la maggior parte pericolosa disfunzione di C++, ecco perché i costruttori di conversione sono 'espliciti' in' std :: complex'. Nuota contro corrente a tuo rischio. –

risposta

6

Per l'aggiunta di numeri complessi di diverse tipologie e altri operatori Vorrei usare le funzioni libere

std::complex<double> operator? (std::complex<double> a,std::complex<float> b){ 
    std::complex<double> result; 
    // implement ? 
    return result; 
} 
std::complex<double> operator? (std::complex<float> a,std::complex<double> b){ 
    return b ? a; 
} 

dove ? è un placehold per l'operatore che si desidera avere. Si noti che questa è una soluzione pre-C++ 11, per un modo molto più bello vedere Jerry Coffins answer.

Per aggiungere un numero a un complesso, come in 1+c, non vorrei fare lo sforzo di scrivere un operatore, ma semplicemente utilizzare c+1 invece (in realtà io non sono sicuro se questo funziona per std::complex ma sarei sorpreso se non).

+0

'c + 1' e' 1 + c' non sono entrambi definiti se 'c' è' complesso '. Sono entrambi definiti se 'c' è' complesso '. –

7

L'aggiunta di questi sovraccarichi come funzioni libere è probabilmente un buon modo per svolgere il lavoro come qualsiasi. Tuttavia, non scriverei un codice separato per ogni possibile coppia di tipi di operandi, che diventerebbe noioso molto rapidamente.

Invece, si desidera senza dubbio scrivere una funzione di modello per gestire qualsiasi coppia di tipi di operandi. Qualcosa su questo ordine generale:

template <class T, class U> 
auto operator*(T const &a, U const &b) -> typename std::common_type<T, U>::type 
{ 
    // code to produce the equivalent of: return a * b; 
} 

In questo modo se si moltiplica un complex<double> da un int e un complex<float> da un double (etc.) non è necessario duplicare la funzione per ogni combinazione possibile (e se si tenta di combinare due tipi che non hanno un tipo comune come complex<double> e std::string, semplicemente non verrà compilato).

In questo caso, riempire il corpo è abbastanza semplice: abbiamo input di due tipi diversi, ma sappiamo (o possiamo dedurre) un tipo comune che è compatibile con entrambi. Vogliamo lanciare ogni ingresso a quel tipo comune, e fare l'operazione sui risultati della fusione:

template <class T, class U> 
auto operator*(T const &a, U const &b) -> typename std::common_type<T, U>::type 
{ 
    using ret_type = typename std::common_type<T, U>::type; 
    return ret_type(a) * ret_type(b); 
} 
non
+1

Mi sento un po 'imbarazzato per la mia risposta ora;) – user463035818

+1

Non stai implementando l'operatore a * b in termini di se stesso? Come dovrebbe funzionare? – MikeMB

+0

@MikeMB: Scusate, suppongo di non averlo indicato, ma il corpo era inteso solo come pseudo-codice come segnaposto. Vale a dire, lì faresti tutto il necessario per moltiplicare i due elementi e restituire il risultato. Ho modificato per renderlo più evidente e aggiungere un'implementazione reale. –

Problemi correlati