Gather data from loosely coupled classes - c++

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;
};

Related

Strategy & builder design patterns and templates in C++

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.

how to create a class from an identifier?

the title might be a bit misleading, but I want to give some instance of a class an instance of a different class through polymorphism. I think that may have been even more misleading so I'll give an example;
Say I have a class called Spell, that is a parent class to the class Firebolt. I want another class, say Character, to be able to have the spell, 'Firebolt', in an its memory without ever having to #include the files for 'Firebolt'.
Now, I can think of a way that prior games have done this before. By giving each spell (or whatever else specific class type) a static const string ID or name and in spell having some function that can access this ID/name and return a new Firebolt() if they are the same.
This sounds pretty good actually, the problem I'm having is I don't know how to code this. I'm not sure how I can access these ID's from the parent class, and I'm not sure how to make a virtual function that will actually return the correct Spell. Any help would be amazing. I'll also provide the actual class code I'm working with here in case it might help you guys to answer, or someone with a similar problem to solve it.
The parent class;
class Art {
std::string name;
int EPCost;
int castTime;
int AoESize;
public:
Art(std::string n, int cp, int ct, int as):name(n), EPCost(cp), castTime(ct), AoESize(as) {}
virtual ~Art() {}
static Art* findArt(std::string ID);
int getAoESize() {return AoESize;}
std::string getName() {return name;}
int getEPCost() {return EPCost;}
virtual int getBaseDamage() = 0;
};
The subclass;
class FireBolt:public Art {
static const std::string name;
static const int EPCost;
static const int castTime;
static const int AoESize;
static const std::string ID;
public:
FireBolt():Art(name, EPCost, castTime, AoESize) {}
~FireBolt() {}
int getBaseDamage();
};
All you need to do is make your FireBolt::ID public.
class FireBolt:public Art {
public:
static const std::string ID;
...
};
Art* Art::findArt(const std::string& ID)
{
if (ID == FireBolt::ID)
return new FireBolt(...);
...
}

Pointers disappear after calling sub-routine of child class

I am trying to do One class with some features that will be em common with other (Inheritance). This is my principal class:
class SREngineJulius_father {
protected:
bool g2pInit;
Recog *recog;
Jconf *jconf;
public:
bool InitG2P(std::string dic, std::string model, int pos_process_flag=-1);
bool Init_AM(std::string configStr);
};
The two function InitG2P and Init_AM, will make updates in recog and jconf. This updates is something that all child objects of the child class must have.
class SREngineJulius: public SREngineJulius_father
{
DFA_INFO *dfaInfo;
WORD_INFO *wordInfo;
WORD_INFO *wordInfo_init;
Output lastResult;
TListString lastCmdList;
bool startNotifyCallbackLoop;
bool terminate;
bool pause;
DFA_INFO* copy_dfa_info(DFA_INFO* dfa);
DFA_INFO* create_commands_dfa_info();
static void status_recready(Recog *recog, void *dummy);
static void status_recstart(Recog *recog, void *dummy);
static void output_result(Recog *recog, void *dummy);
static void put_hypo_phoneme(WORD_ID *seq, int n, WORD_INFO *winfo);
std::string ReplaceSpace(std::string &str);
std::string RestoreSpace(std::string &str);
public:
bool InitG2P(std::string dic, std::string model, int pos_process_flag=-1);
char* NotifyCallbackLoop(char *ficheiro_wav);//AXY5
int SREngineJulius::Audio_Buffering(char* buffer_audio, int sizefile, int end_flag_, int flag_alocation);//AXY5
void Callbacks();
public:
~SREngineJulius();
bool InitSREngine(std::string recoConfig);
bool DynamicAddCommands(TListString &cmdlist, int startRecog = -1);
bool DynamicAddCommands(std::string cmdlist, std::string sep=" ", int startRecog = -1);
void Release();
};
So the problem is, when I call a routine of the child class, recog and jconf are deleted.
You should make functions in your class that edify the two variables. Try inserting those into a anonymous struct. That way they're easily accessible.
Remember:
. =reference
-> =pointer
Lastly, you are changing recog in a couple of those function declarations.
Try to make sure that the functions are friendly in the functions you make. If they are not, you won' be able to use them.
P.s. children of child classes, these need accessor functions. They have to change the pointers through upward inheritance. So you would want to have the child class of the grandparent have a class that changes it's pointers. You would do that by having a function which accesses the child, in the grandchild. That way you're receding back into the function. That's how it's related.

C++: what is the best way to handle this multi-inheritance?

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;
};

Datatypes and polymorphism

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.