The following is the geometry class, which handles storing and manipulating vertex and index information of a particular 3-dimensional object.
class geometry {
public:
geometry();
~geometry();
unsigned int get_face_count();
unsigned int get_vertex_count();
void add_vertex(vertex v);
void add_face(face f);
void remove_vertex(unsigned int idx);
void remove_face(unsigned int idx);
std::vector<vertex>& get_vdata();
std::vector<face>& get_fdata();
vertex& get_vertex(unsigned int idx);
vertex& get_face(unsigned int idx);
void clear();
void calc_normals();
bool is_empty() const;
protected:
std::vector<vertex> vertices;
std::vector<face> faces;
};
The following is a base Builder class, which can't be instantiated:
class geometry_creator : public geometry {
protected:
bool normalsWerePredefined;
/* Unused */
bool texturesWerePredefined;
public:
geometry* build();
};
The build(); method for all derived Builder classes are the same, which looks like this (for context):
/* Liskov principle (upcasting) */
geometry* geometry_creator::build() {
if (!normalsWerePredefined) calc_normals();
geometry* g = new geometry(*this);
return g;
}
Next is the geometry_obj class, which inherits geometry_creator (Builder). This class is responsible for building a geometry object from a specified .OBJ file. I created a builder class because there exists other ways to build geometry objects, such as procedural methods.
class geometry_obj : public geometry_creator {
private:
std::string filename;
std::fstream file;
std::stringstream stream;
std::string element;
enum entry {
VERTEX,
VERTEX_TEXTURES,
VERTEX_NORMALS,
FACE
};
inline static const std::map<std::string, entry> map = {
{"v", VERTEX},
{"vt", VERTEX_TEXTURES},
{"vn", VERTEX_NORMALS},
{"f", FACE}
};
/* Our strategies. */
vec_strategy<3, float> vec3f_strategy;
vec_strategy<2, float> vec2f_strategy;
vec_strategy<3, unsigned int> vec3i_strategy;
protected:
unsigned int vIndex, vnIndex, vtIndex, fIndex;
public:
geometry_obj(std::string filename);
};
The vec_strategy members give us the context for my question.
Lastly, the next two classes define the interface for a particular Strategy and then the concrete Strategy class.
template<typename T>
/* Strategy interface. */
class objreader_strategy {
public:
virtual T execute(std::stringstream& stream) = 0;
};
/* Concrete strategy implementation. */
/* int L is data length, typename S is datatype of data to acquire. */
template<int L, typename S>
class vec_strategy : objreader_strategy<glm::vec<L, S>>{
private:
std::array<S, L> _data;
public:
vec_strategy();
~vec_strategy() = default;
virtual glm::vec<L, S> execute(std::stringstream& stream);
};
In most Strategy design pattern implementations, the Context (our derived Builder class geometry_obj) has a setStrategy method and executeStrategy method. With this implementation I could not find a way to create a method parameter that could handle a base pointer to obj_strategy for setStrategy nor a way to store a theoretical currentStrategy member, given the relatively complex template parameters.
My question is now: what solution exists to store a currentStrategy object in the given context (templates for T, L, and S)? What better method exists to prevent the instantiation of multiple vec_strategy objects in the geometry_obj class, and instead use one member that certain methods in geometry_obj could act upon when needed?
I have not tested to see if this code runs as expected yet, but it does compile. So part of my question also asks: how well is this program designed? - from your perspective.
If any additional context is required, such as implementation of these classes, I would gladly provide it. I'm also terribly sorry for my naming conventions.
Related
I am building a matlab MEX function using the matlab c++ data api. My mex function accepts a struct with some fields of varying size, type and name as an input. The exact makeup of this struct could vary and is defined outside the scope of the program, but I know all the possible combinations of the constituent fields ahead of time. We will call this parameter called 'Grid', and Grid is passed to a helper function.
In this helper function, I would like to generate an instance of a derived class where the specific type of derived class will either depend on/correspond to the specific combination of the fields of Grid. The idea is that I can extract the fields of Grid and use them to create the instance of the correct derived class. I would like to achieve this without the need to rewrite my code every time I add a new derived class with a different possible combination of fields. How could I do this? I am open to alternate approaches and strategies as well.
For example, Grid might be defined in the matlab environment like:
Grid = struct('XPSF',X(:),'ZPSF',Z(:),'xe',Trans.ElementPos(:,1)*wvlToM,'TXDelay',TXdelay(:,8));
Then handled by the mex function and passed to the helper function whose definition looks like:
void extractFields(matlab::data::StructArray& Grid);
Currently, Grid can also be composed of a single value in place of XPSF or ZPSF. I anticipate possibly adding other fields to Grid in the future. For each of these possible combinations, I have a derived class that has some unique overridden functions:
class Beamform {
public:
//Constructor
Beamform();
virtual ~Beamform() {}
template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); }
virtual void calcIDXT(...);
};
class bfmPlaneWave : public Beamform
{
public:
double theta;
Eigen::VectorXd xe, XPSF, ZPSF, dTX;
template<typename Derived>
bfmPlaneWave(double& angle, ...);
template<typename Derived>
void calcIDXT(...) override;
};
class bfmXRflMTX : public Beamform {
public:
double theta, zCoord;
Eigen::VectorXd xe, XPSFin, XPSFout, dTX;
template<typename Derived>
bfmXRflMTX(double& angle, ...);
template<typename Derived>
void calcIDXT(...) override;
};
class bfmZRflMTX : public Beamform {
public:
double theta, xCoord;
Eigen::VectorXd xe, ZPSFin, ZPSFout, dTX;
template<typename Derived>
bfmXRflMTX(double& angle, ...);
template<typename Derived>
void calcIDXT(...) override;
};
I would start by declaring a common pattern for construction. Something like this:
class Beamform
{
public:
virtual void calcIDXT(...) = 0;
virtual ~Beamform() = default;
};
class bfmPlaneWave: public Beamform
{
public:
/** Return nullptr if not compatible */
static bfmPlaneWave* fromGrid(matlab::data::StructArray&);
virtual void calcIDXT(...) override;
};
class bfmXRflMTX: public Beamform
{
public:
/** Return nullptr if not compatible */
static bfmXRflMTX* fromGrid(matlab::data::StructArray&);
virtual void calcIDXT(...) override;
};
Then you could have a simple, central factory function that you extend as required:
/**
* Option 1: Use a central dispatch function which can be updated with a
* simple two-liner
*/
std::unique_ptr<Beamform> beamformForGrid(matlab::data::StructArray& Grid)
{
std::unique_ptr<Beamform> rtrn;
if(rtrn.reset(bfmPlaneWave::fromGrid(Grid)), rtrn != nullptr)
return rtrn;
if(rtrn.reset(bfmXRflMTX::fromGrid(Grid)), rtrn != nullptr)
return rtrn;
// insert more here
return rtrn;
}
However, if I understand you correctly, this is something that you don't want. In that case you could use a central registry and global constructors. Global constructors (those for global variables) are run when a DLL is loaded. This is similar to how for example CppUnit registers its unit tests.
class AbstractBeamformFactory
{
public:
virtual ~AbstractBeamformFactory() = default;
/** Return nullptr if not compatible */
virtual Beamform* fromGrid(matlab::data::StructArray&) = 0;
};
/**
* Registers existing factories
*
* Follows the singleton pattern.
* Yes, it is frowned upon, but if it works, it works.
*/
class BeamformRegistry
{
/**
* Protects the list of factories
*
* A bit overkill seeing how neither Matlab nor global constructors are
* particularly multithreaded, but better safe than sorry
*/
mutable std::mutex mutex;
std::vector<AbstractBeamformFactory*> factories;
public:
/**
* Retrieves singleton instance
*
* This isn't a global variable because we need to use it in other
* global constructors and we can't force a specific order between
* global constructors
*/
static BeamformRegistry& globalInstance();
void add(AbstractBeamformFactory* factory)
{
std::lock_guard<std::mutex> lock(mutex);
factories.push_back(factory);
}
void remove(AbstractBeamformFactory* factory)
{
std::lock_guard<std::mutex> lock(mutex);
factories.erase(std::find(factories.begin(), factories.end(), factory));
}
std::unique_ptr<Beamform> beamformForGrid(matlab::data::StructArray& Grid) const
{
std::unique_ptr<Beamform> rtrn;
std::lock_guard<std::mutex> lock(mutex);
for(AbstractBeamformFactory* factory: factories)
if(rtrn.reset(factory->fromGrid(Grid)), rtrn != nullptr)
break;
return rtrn;
}
};
/**
* Implements AbstractBeamformFactory for a specific type of beamformer
*
* Create a global variable of this type in order to add it to the global
* BeamformRegistry
*/
template<class BeamformImplementation>
class BeamformFactory: public AbstractBeamformFactory
{
bool registered;
public:
explicit BeamformFactory(bool registerGlobal=true)
: registered(registerGlobal)
{
/* don't move this to the base class to avoid issues around
* half-initialized objects in the registry
*/
if(registerGlobal)
BeamformRegistry::globalInstance().add(this);
}
virtual ~BeamformFactory()
{
if(registered)
BeamformRegistry::globalInstance().remove(this);
}
virtual Beamform* fromGrid(matlab::data::StructArray& Grid) override
{ return BeamformImplementation::fromGrid(Grid); }
};
/* in CPP files */
BeamformRegistry& BeamformRegistry::globalInstance()
{
static BeamformRegistry instance;
return instance;
}
/*
* Make global variables to add entries to registry.
* These can be scattered across different cpp files
*/
BeamformFactory<bfmPlaneWave> planeWaveFactoryInstance;
BeamformFactory<bfmXRflMTX> XRflMTXFactoryInstance;
Now you can simply call BeamformRegistry::globalInstance().beamformForGrid(Grid) to access all registered beamform implementations and to extend the number of implementations, you just scatter factory instances across your cpp files.
One thing I'm unsure about is how this interacts with MEX. When does Matlab load its extensions? If this only happens in some form of lazy fashion, the global constructors may not execute soon enough. I guess it is worth checking with a few print statements.
I have two databases of different types of objects with some common functions so I thought to create a parent class with the definitions of the common functions. The idea is that these functions have to do the same operations even though the type of objects is different. A silly example:
class Database
{
public:
// retrieve size of the dataset
int Size() const {return list_.size();}
};
class DerivedDatabase : public Database
{
private:
// list of dataset objects
std::vector<Object1> list_;
};
class DerivedDatabase2: public Database
{
private:
// list of dataset objects
std::vector<Object2> list_;
};
One solution is to define the function as virtual Size() const =0 and then have the derived classes override it. However the idea is to have it already implemented for when I have to create new types of DataBases. Is there a way to specify a posteriori the variable type in the derived classes? The two derived databases are inherently different and they behave completely differently except for some functions, which are common. Thus they have to be separate objects
You may use CRTP to factorize code, something like:
template <typename T> class Database
{
// T should have a container named list_
public:
// retrieve size of the dataset
int Size() const { return AsDerived().list_.size(); }
private:
const T& AsDerived() const { return static_cast<const T&>(*this); }
T& AsDerived() { return static_cast<T&>(*this); }
};
And then
class DerivedDatabase : public Database<DerivedDatabase>
{
friend class Database<DerivedDatabase>;
private:
std::vector<Object1> list_;
};
class DerivedDatabase2 : public Database<DerivedDatabase2>
{
friend class Database<DerivedDatabase2>;
private:
std::vector<Object2> list_;
};
Note that DerivedDatabase and DerivedDatabase2 doesn't share a common base type here
Live example
Sure, that what templates are for:
class Database {
virtual int size() = 0;
public:
// retrieve size of the dataset
int Size() const {return size();}
}
template<typename T>
class DerivedDatabase: public Database {
std::vector<T> list_;
int size() const {return list_.size();}
}
In a software project, I've done my best to make the classes loosely coupled. Now I'm struggling to get the scattered data (from objects of the loosely coupled classes) into a data object. This data object (e.g. for logging) is predefined and has to be filled with data from objects of several classes.
As the real code is proprietary, I've written the code below which should illustrate my problem:
class Gear {
public:
Gear(unsigned int amount);
~Gear();
void shiftUp();
void shiftDown();
private:
const unsigned int amount;
unsigned int current;
};
class Speedometer {
public:
Speedometer();
~Speedometer();
void display() const;
private:
double currentSpeed;
};
class Bike {
public:
Bike(unsigned int nrWheels, Gear& gear, Speedometer& speedometer);
~Bike();
void peddle() const;
void break() const;
private:
const unsigned int nrWheels;
Gear& gear
Speedometer& speedometer;
};
class Cyclist {
public:
Cyclist(const std::string name, Bike& bike);
~Cyclist();
void ride();
private:
const std::string name;
Bike& bike;
};
class Factory {
public:
Factory();
~Factory();
Cyclist& build() const;
};
struct PredefinedData {
PredefinedData();
~PredefinedData();
std::string cyclistName;
unsigned int nrWheels;
unsigned int currentGear;
double currentSpeed;
};
A Factory (object) builds a Cyclist (object) with all objects that it references (recursively). The state of all these objects will change during the execution of the program. In order to e.g. log the state of a Cyclist object with all its references, an object from the PredefinedData class is used. This object has to be filled with data from Cyclist and its references.
Some thoughts/tests of my own:
I've tried giving every class a reference of the PredefinedData object, but that meant that private data of objects would be known by other objects.
I've tried a Filler object that provides functions to fill the PredefinedData object, but it feels like duplicating the PredefinedData class.
I've also considered inheriting a class from several classes to be able to give every class access to just the data it should have access to/fill.
How would you solve this? Is there a design pattern for this situation?
I'd do this:
class Cyclist {
public:
Cyclist(const std::string name, Bike& bike)
: data(name), bike(bike) {}
const PredefinedData& getPredefinedData()
{
data.nrWheels = bike.getNrWheels();
data.currentGear = bike.gear.getCurrent();
data.currentSpeed = bike.speedometer.getSpeed();
return data;
}
private:
PredefinedData data; // includes name, used as a cache
Bike& bike;
};
A page is basically a fixed size array of a type - but it provides other functionality which isn't important for this question. Specifically, each page has a recordOffset which implies that the record IDs for the page are sequential and begin at this index (a page can be viewed as a discreet arbitrary segment of a larger array)
class AbstractPage
{
protected:
unsigned int recordOffset;
public:
AbstractPage(unsigned int recordOffset);
virtual ~AbstractPage();
// a mixture of pure and non-pure virtual functions
virtual string toString() const;
virtual unsigned int getCount() const = 0;
virtual PageType pageType() const = 0;
};
class IntegerPage : public AbstractPage
{
public:
vector<int> data;
IntegerPage(const vector<int>& data);
virtual ~IntegerPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
};
class FloatPage : public AbstractPage
{
public:
vector<float> data;
FloatPage(const vector<float>& data);
virtual ~FloatPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
};
I don't want to use templates for this because these pages get used liked this;
LinkedList<AbstractPage> pages;
I will use the interface methods provided by AbstractPage to interact with the page in most cases. When I need to read/write the data directly I will know the type separately and use:
dynamic_cast<FloatPage>(abstractPage).data[0] = 12.34;
So far so good, but here is the dilemma; I need to extend every type to create an indexed version of the page:
class AbstractIndexedPage
{
public:
// this is instead of the recordOffset of AbstractPage
vector<unsigned int> recordIds;
};
class IndexedIntegerPage : public AbstractIndexedPage, public IntegerPage
{
};
Now I want to be able to do this:
AbstractIndexedPage sort(const AbstractPage& page)
{
// Sorting will swap around the data and therefore we need to keep track of the
// record IDs in an Indexed page.
// If the incoming concrete type is IntegerPage, the output will be
// IndexedIntegerPage
}
The problem is the returned object will not have the interface to AbstractPage:
AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getCount(); // can't do this!
dynamic_cast<AbstractPage>(sortedPage).getCount() // can do this, but pretty messy
From what I've read multiple inheritance in all but select cases means your code is basically designed badly. In this case there is multiple inheritance from two non-interfaces, both of the classes will have a constructor (and virtual destructor) but will only ever directly deal with the instance variables they provide.
My options are:
AbstractIndexedPage extends AbstractPage and use virtual inheritance since there will now be two AbstractPage. But that will give me the complete interface. But isn't this a naughty hack?
Just duplicate data or recordIds instance variables in IndexedIntegerPage and IntegerPage to give the same functionality without the need for inheritance.
Design the architecture differently?
Thanks
You can use delegation to do this work. For example, at AbstractIndexedPage:
class AbstractIndexedPage
{
public:
// this is instead of the recordOffset of AbstractPage
vector<unsigned int> recordIds;
AbstractClass* getPage() { return page;};
private:
AbstractClass *page;
};
and do something like that:
AbstractIndexedPage sortedPage = sort(originalPage);
sortedPage.getPage()->getCount(); // can't do this!
of course, verifying all possible errors or exeptions.
P.S. Someone will tell you to use smart pointer and I will agree with them, but, for simplicity, I just use plain pointer either
I was going to post this in comments, but the code will look terrible. You might consider abstracting at a lower level: create an AnyType, and just one Page Type based on it:
union AnyType {
float f;
int i;
};
class AnyPage : public AbstractPage
{
public:
enum PageDataType {FloatPage, IntPage};
vector<AnyType> data;
AnyPage(const vector<int>& data); //creates an 'IntPage'
AnyPage(const vector<float>& data); //creates a 'FloatPage'
virtual ~AnyPage();
// our concrete implementation
virtual unsigned int getCount() const;
virtual PageType pageType() const;
private:
PageDataType myType;
};
Then you can create your linked lists of AnyPage, and as you said, you already know which kind of page you are dealing with when you want to access the data:
anyPage.data[0].f = 12.34;
Then, for the indexed variety, it is no longer multiple inheritance:
class AnyIndexedPage : public AnyPage
{
public:
// this is instead of the recordOffset of AnyPage
vector<unsigned int> recordIds;
};
I have a design question. I want custom datatypes implementing an interface. For example, using templates is simply (maybe next design isn't correct -because I can do a generic class instead of the next- but clarifies my goal):
template <typename T>
class IDatatype
{
public:
virtual T getData() const = 0;
virtual void setData(T pData) = 0;
};
class MyChar: public IDatatype<char>
{
public:
void setData(char pData){...}
char getData() const{...}
private:
char _data;
};
class MyInt: public IDatatype<int>
{
public:
void setData(int pData){...}
int getData() const{...}
private:
int _data;
};
IDatatype<int> *data = new MyInt(); // parametrized interface, bad idea :(
data->getData(); // it works ok
From previous classes, it is easy to get the attribute corresponding to each _data class member. My question:
Is there any way (change design, etc.) to implement generic setter and getter in IDatatype
and for any type and thus manipulate the _data attribute of each class
without using templates in the interface?
For example:
class IDatatype
{
public:
// pure virtual getters and setters for specialized _data fields. Here is my design question.
};
class MyChar: public IDatatype
{
public:
void setData(char pData){...};
char getData(){...};
private:
char _data;
};
class MyInt: public IDatatype
{
public:
void setData(int pData){...};
int getData(){...};
private:
int _data;
};
IDatatype *intData = new MyInt(); // no parametrized interface!
intData->getData(); // how can I create this method from IDatatype?
IDatatype *charData = new MyChar();
charData->getData(); // the same here
NOTE: I have no good english, apologize for any errors :)
You could probably achieve this in 3 ways, none as elegant and error free as using a template
Define your data as a union of int/float/char in the base class and act on this union from the set/get methods of the base class. The entire VB (old VB 6) class system works on such a data type called VARIANT.
Return void * from base class and cast and use as appropriate - yuck & good luck!!.
Return the base interface reference itself from the getData which though appearing to be meaningful, has no meaning at all.
4.