Is it bad design to have an abstract class inherit from another abstract class?
Io non la penso così Lo sto usando in una grande applicazione C ++ al lavoro da più di vent'anni.
Presenterò una vista semplificata dei tipi di entità con cui si occuperà un'applicazione CAD.
Di solito c'è una classe base comune che si occupa di nomi di oggetti, di allegare dati specifici dell'utente a un oggetto, ecc. Tuttavia, ci sono pure funzioni virtuali per fare una copia dell'oggetto, per scrivere un oggetto in un file o trasmettere e leggere da un file o stream, ecc.
class BaseEntity
{
public:
void setName(std::string const& name);
std::string const& getName() const;
void setAttribute(std::string const& attName, int data);
void setAttribute(std::string const& attName, double data);
void setAttribute(std::string const& attName, std::string const& data);
// Return false if attribute with the given data type does not exist.
bool getAttribute(std::string const& attName, int& data);
bool getAttribute(std::string const& attName, double& data);
bool getAttribute(std::string const& attName, std::string& data);
BaseEntity* makeCopy() const = 0;
virtual std::ostream& write(std::ostream& out) const = 0;
virtual std::istream& read(std::istream& in) const = 0;
};
Alcuni tipi di livelli foglia sono Part
, Assembly
, Face
, Edge
, Vertex
.
Part
e Assembly
di solito hanno una classe base. Un Assembly
è concettualmente un compoiste Part
. Quindi, hanno molte funzionalità comuni che possono essere acquisite in una classe base intermedia, come Model
.
modello di classe: BaseEntity pubblica
{
pubblico:
void setParent(Model* model);
Model* getParent() const;
// Assume there is a type called Transform
Transform getTransformToParent() const;
// More convenience functions to position a Part/Assembly
// in the parent Model.
//
// ...
//
virtual double getVolume() const = 0;
virtual double getSurfaceArea() const = 0;
// More query functions common to Part and Assembly
// ...
//
};
Face
, Edge
e Vertex
sono entità topologiche del modello BREP. La funzionalità comune di queste classi può essere catturata in un clas intermedio, come TopologyEntity
.
class TopologyEntity : public BaseEntity
{
public:
void setID(int id);
int getID() const;
void setPart(Part* part);
Part* getPart() const;
// More convenience functions for all derived classes.
// ...
//
};
Né Model
né TopologyEntity
sono classi concrete. Definiscono le astrazioni che hanno senso. Possono implementare funzionalità comuni. Possono aggiungere più funzioni virtuali che le classi concrete devono implementare.
Ecco un diagramma di tale gerarchia di classi.