2013-03-18 16 views
5

Mi piacerebbe distinguere chiaramente tra punti 3D e 2D nel mio codice. La soluzione ovvia sarebbe quella di avere classi separate.Come proibisco la conversione implicita alla classe base?

D'altra parte le conversioni da punti 3D con z = da 0 a 2D punti sono abbastanza comuni. Pertanto vorrei utilizzare una classe di base comune in modo da poter eseguire tali conversioni sul posto in memoria. Per mantenere distinti i tipi, vorrei vietare la conversione implicita a quella classe base. È fattibile?

Oppure esiste un modo diverso per creare tipi diversi con funzioni simili come questa?

+3

hm, potresti voler dare un'occhiata qui (suggerimento: 'explicit') :-) http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean – Najzero

+0

Puoi dare un esempio di questa conversione "in-place in memory" di cui stai parlando? a priori, penso che qualsiasi eredità pubblica tra un 2D e un punto 3D sembra innaturale e confusionario. – juanchopanza

+0

Non vedo come una classe base comune dovrebbe consentire comunque di convertire un punto 3D in un punto 2D sul posto. Supponiamo che 'B' sia una base di' 2Dpoint' e '3Dpoint', con le coordinate' x' e 'y' memorizzate in' B'. Supponiamo inoltre di avere un'istanza di '3Dpoint' e di volere un'istanza di' 2Dpoint' senza copiare nulla. Cosa succederà? –

risposta

1

Se si desidera accedere alla parte 2d del proprio vettore 3d senza alcuna copia, esiste davvero un'unica soluzione ragionevole.

class Vector2d { ... }; 
class Vector3d { 
    Vector2d part2d; 
    double z; 
public: 
    Vector2d& as2d() { return part2d; } 
}; 

eventuali imbrogli di successione a base sono molto suscettibile di provocare una cattiva progettazione, un comportamento indefinito, o entrambi.

+0

A seconda delle funzioni che operano su quei punti può essere utile poter accedere a membri privati ​​o protetti ma tu sei corretto: in caso contrario, la soluzione dovrebbe essere preferibile. – Sarien

2

Questo non risponde alla tua domanda, ma per risolvere il tuo problema potresti fare un metodo nella classe 3D restituendo un punto 2D quando richiesto.

2

Si potrebbe derivare le classi figlie privatamente:

class PointBase { 
    // ... 
}; 

class Point2D : private PointBase { 
    // ... 
}; 

class Point3D : private PointBase { 
    // ... 
}; 

effetto collaterale di questo approccio è che anche tutti i membri pubblici della PointBase sarebbero inaccessibili dall'esterno, in modo che le sottoclassi avrebbe dovuto renderli accessibili in modo esplicito, o fornendo loro metodi proxy o specificandoli con la parola chiave using. Ecco perché andrei in questo modo solo se la logica comune in PointBase è considerevole e averla implementata in un singolo luogo porta più vantaggi rispetto allo svantaggio menzionato.

+0

Vero, sono solo la vecchia scuola che spesso dimentica facilmente le nuove funzionalità di C++. Ma anche se "usare" sicuramente è meno digitato, lo sviluppatore deve ancora preoccuparsi di rendere accessibili i metodi rilevanti da "PointBase". – mity

+0

Modificata la risposta per includerla. – mity

1

Se il punto viene memorizzato come un vettore, si potrebbe definire il 3D e le classi di punti 2D come classi templated con int parametro che specificheranno conteggio dimensione:

template<int dimensions> class Point { 
    vector<int> coords; 
    Point() : coords(dimensions) {} 
    .... 
    template<int other_dimensions> convertToPoint() const 
    { 
     // Handle different options here like: 
     // dimensions > other_dimensions 
     // dimensions < other_dimensions 
     // et cetera 
    } 
}; 

e creare un'istanza classi punto:

typedef Point<2> Point2D; 
typedef Point<3> Point3D; 
Point2D pt = Point3D(1, 2, 3).convertToPoint<2>(); // Point2D(1, 2); 
Point3D pt = Point2D(4, 5).convertToPoint<2>(); // Point3D(4, 5, 0); 

In questo modo, avrai la stessa logica ma tipi completamente diversi e conversioni facili. Per non parlare del fatto che dovrai definire solo una classe anziché due separate.

Problemi correlati