2012-02-06 22 views
7

Sto avendo un momento difficile la formazione di una questione di quello che sto cercando di chiedere quindi lasciate che vi faccia un esempio:operatore di base sovraccarico sintassi in C++

dire che stiamo lavorando su un sistema 3D in cui abbiamo definito una classe vettoriale, Vec3. Sovrapponiamo alcuni operatori aritmetici per evidenti risonanze. Tra questi sovraccarichiamo l'operatore * in modo che restituisca il prodotto punto di due vettori. Ora il nostro codice dovrebbe essere simile a questa:

class Vec3{ 
private: 
    float x, y, z; 
public: 
    float operator*(const Vec3&) const; //dot product 
. 
. 
. 

Ora dicono che noi vogliamo essere in grado di scalare il nostro vettore utilizzando l'operatore * con qualcosa, per esempio un galleggiante. Ciò potrebbe essere fatto dichiarando quanto segue:

Vec3 operator*(const float) const; 
    friend Vec3 operator*(const float, const Vec3&); 

Questo yeilds due sovraccarichi e Mi chiedo se c'è un modo per farlo con un solo, cioè diciamo dichiariamo questo invece di queste due linee:

friend Vec3 operator*(const Vec3&, const Vec3&); 

e quindi aggiungere valori predefiniti per Vec3 ctor per gestire la conversione da float.

Quest'ultimo esempio dovrebbe funzionare per:

Vec3 someVec3 = 1.0 * otherVec3; //through friend Vec3 operator*(const float, const Vec3&) 
, tuttavia, non

per questo:

Vec3 someVec3 = otherVec3 * 1.0; 

come il compilatore non saprebbe quale delle due utilizzare:

friend Vec3 operator*(const float, const Vec3&); //the one we want to use 
or 
    float operator*(const Vec3&) const; //the one for the dot product 

Qualche suggerimento?

Grazie!

+3

Cosa c'è che non va con due sovraccarichi? Come si fa notare, quando si cerca di semplificare eccessivamente si crea un'ambiguità piuttosto spiacevole ... –

+2

L'unica cosa che farei diversamente, è rendere entrambe le versioni di scalare molte funzioni amico invece di essere membro, in modo che il codice hanno la stessa simmetria dell'operazione stessa. –

+0

Sarebbe inefficiente costruire un vettore solo per passare un float. Questa sarebbe un'inefficienza in fase di esecuzione, ma una funzione extra sovraccaricata potrebbe essere inline. – QuentinUK

risposta

5

In questo caso avrei inizialmente sconsiglio l'overloading degli operatori, perché come sono i vostri utenti di sapere se * rappresenta punto o prodotto vettoriale (entrambi sono significati ragionevoli a seconda dell'uso del cliente previsto). In realtà suggerirei semplicemente di non supportare operator* e farlo con dot, cross e scale membri. Quindi non devi preoccuparti di sovraccarichi multipli ed è chiaro ai tuoi utenti cosa stanno ottenendo.

Tuttavia, se si vuole andare avanti con gli operatori, non c'è niente di sbagliato nell'avere due sovraccarichi. La creazione di un dummy Vec3 per eseguire il ridimensionamento non solo è semanticamente corretta, ma aggiungerà una piccola quantità di sovraccarico non necessario.

1

Non c'è nulla di sbagliato in un paio di sovraccarichi, soprattutto se non possono essere facilmente implementate in termini di vicenda:

Vec3 operator*(const float scale, const Vec3& vec) 
{ return vec * scale; } 

E 'difficile ottenere più semplice di così!

2

Boost.Operators può fare la maggior parte del lavoro della piastra della caldaia per voi. Es .:

class Vec3 
    : boost::multipliable2<Vec3, float> 
{ 
public: 
    // ... 

    Vec3 operator*=(float); 
    // Vec3 operator*(Vec3, const float&) and 
    // Vec3 operator*(const float&, Vec3) auto-generated 
    // by multipliable. 
};