2014-08-28 14 views
8

Sto cercando di implementare una suite di tipi di punti utilizzati in GIS, che sono 2D (xy), 3D (xyz o xym) o 4D (xyzm). La coordinata M è una coordinata della misura e le altre dovrebbero essere ovvie. Tuttavia, non riesco a capire come rendere la classe condivide i membri x e dalla classe Point. Qui è il mio codice:Polymorphism in C++ con ereditarietà condivisa

#include <iostream> 

class Point { 
    public: 
    double x, y; 
    Point (double xNew, double yNew) : x(xNew), y(yNew) {}; 
}; 

class PointZ : public Point { 
    public: 
    double z; 
    PointZ (double xNew, double yNew, double zNew) : 
     Point(xNew, yNew), z(zNew) {}; 
}; 

class PointM : public Point { 
    public: 
    double m; 
    PointM (double xNew, double yNew, double mNew) : 
     Point(xNew, yNew), m(mNew) {}; 
}; 

class PointZM : public PointZ, public PointM { 
    public: 
     PointZM (double xNew, double yNew, double zNew, double mNew) : 
      PointZ(xNew, yNew, zNew), PointM(xNew, yNew, mNew) {}; 
}; 

int main() { 
    Point p (1, 2); 
    PointZ pZ (1, 2, 3); 
    PointM pM (1, 2, 4); 
    PointZM pZM (1, 2, 3, 4); 
    std::cout << "Point: " << sizeof(p) << std::endl; 
    std::cout << "PointZ: " << sizeof(pZ) << std::endl; 
    std::cout << "PointM: " << sizeof(pM) << std::endl; 
    std::cout << "PointZM: " << sizeof(pZM) << std::endl; 
} 

di stampare le dimensioni delle quattro istanze di ogni classe:

Point: 16 
PointZ: 24 
PointM: 24 
PointZM: 48 

mi aspettavo l'ultimo PointZM essere 32 byte, come avrebbe dovuto x, y, z e m membri. Come posso ottenere le due classi ereditate PointZ e PointM per condividere i membri ereditati Point? È il modo di ottenere l'unione di due classi? Sono un novizio in C++ con questo argomento.

La motivazione sul perché disturbarsi con l'ereditarietà non è evidente con le geometrie dei punti semplici. Tuttavia, quando si sviluppano ulteriori tipi di geometria, come LineString (2D), LineStringZ (3D), LineStringM (3D) o LineStringZM (4D), avrebbero un metodo length che sarebbe diverso se esistesse una dimensione Z. Il metodo di lunghezza verrebbe calcolato in modo diverso solo se esiste una dimensione Z e non vorrei raddoppiare gli sforzi per aggiungere questo alle classi LineStringZ e LineStringZM.

+4

'PointZM' ha due istanze' Punto'. Ad ogni modo, l'ereditarietà non sembra proprio qui. Non direi un punto 4D * è un punto * 2D. – juanchopanza

+3

Controlla le classi di base virtuali; ma l'ereditarietà qui non è probabilmente una buona idea. –

+0

I modelli di classe potrebbero essere un'idea migliore qui? Di nuovo, sono un novizio in questo territorio. – user3985527

risposta

4

La risposta diretta alla tua domanda è utilizzare virtual inheritance. Ciò farebbe in modo che PointZM contenga solo un punto, anziché due. Potresti decidere in seguito che questo non vale la pena, e invece implementare solo PointZ, PointM e PointZM separatamente, ma dipende da te.

Sul mio sistema, l'ereditarietà virtuale aggiunge 8 byte a ciascun tipo virtualmente derivato, e PointZM rimane della stessa dimensione perché i 16 byte del Punto extra in esso contenuto vengono rimossi, ma ora abbiamo due puntatori extra memorizzati per la base virtuale classi. Quindi le dimensioni sono le seguenti:

Point: 16 
PointZ: 32 
PointM: 32 
PointZM: 48 
+0

[OPINIONE] Anche se è corretto, vorrei evitare l'ereditarietà virtuale (e virtuale nulla) in questo caso. Probabilmente ci sarà una grande serie di questi e in tal caso ogni byte conta. Come ho scritto nei commenti della domanda principale, vorrei andare per il POD separato. [/ OPINIONE] –

+0

@Laethnes: farei lo stesso di te se si desidera ottenere prestazioni elevate. –

5

C'è geometria 2D, geometria 3D e geometria 4D. La geometria 3D non è un'istanza raffinata di geometria 2D, è una bestia completamente diversa. Allo stesso modo la geometria 4D non è un caso speciale di geometria 3D.

L'ereditarietà pubblica è destinata ad esprimere la relazione -a. Non esiste una tale relazione tra geometrie dimensionate diversamente.

L'ereditarietà non pubblica può essere utilizzata per la condivisione del codice, ma non è chiaro quale codice possa essere condiviso tra casi 2D, 3D e 4D.

Tuttavia, tutte queste geometrie sono casi di geometria generica a N dimensioni, N è un parametro. Sarebbe naturale modellarlo con un modello di classe.

template <size_t N> 
    class Point 
    { 
     std::array<double, N> coord; 
     // ... rest of the code ... 
    };