I have a couple of base/interface classes each of which has several derived classes. I have a need to store metadata on each derived class that has a lot of overlap, but different values.
I also have a Factory class for creating instances of the derived classes that's implemented as a singleton and has a few macros. For example, you'd:
REGISTER_COMPONENT("MyComponent", MyComponentClass);
// create an instance of each component
BaseComponent *base;
foreach(QString component, ComponentRegister::componentList())
{
base = ComponentRegister::create(component);
// do stuff with base
}
The question is: how and where to store the metadata from a solid design viewpoint.
I could store the data in the ComponentRegister as a QMap structure. When someone registers a component, they could also register its metadata with something like
REGISTER_COMPONENT_METADATA("MyComponent", MyMap);
If the QVariant::isValid() for a particular key, you know the metadata is set and available.
Another way would be static class variables or maybe a static class QMap.
I see advantages and draw backs to both. Most of the metadata are things like "path to QResources for this class" which is not tightly coupled to the business logic of the class itself.
Another issue with the static class variable method comes into play with inheritance. You can't enforce overriding of static class variables like you can with pure virtual functions. So if someone forgets...it could be unclear where in the inheritance tree the values are coming from. If you require access to the metadata through a series of pure virtual "getters" then setting of the MetaData is spread across all implementations of the Base class.
With data held, set, and looked up in the Register if you needed to make changes (like changing the root path for resources), you could do so at a single point...in the class registration calls, probably a header or wrapped in a application Utility function. With static data, you'd have to edit each class declaration.
Open to suggestions and thanks!
If data related to an object isn't specific to a single instance, as the path in your example, my designs usually include a class which manages my collection of objects. That's where I put the meta data.
example:
class zoo { std::vector<animals> zoo_animals; size_t count; }
count is metadata about the animals.
Related
I am facing this problem:
An upstream application defines a class (e.g. box), and a member (say property) with a base class type. I would make a derived class for that member, add new members and methods without updating their application.
Essentially I do box->property = make_shared<myProperty>(). Is there a way to keep the interface of calling the members and methods the same? That is, to access a property using box->property->length or box->property->GetWeight(), rather than dynamic_pointer_cast<myProperty>(box->property)->GetWeight(). The challenge here is they won't update the base property class, and I am not supposed to change box. But we wish to keep the interface the same so our customers won't complain.
Is it possible? If not, how could we do to best keep the main app and my plugin relatively independent while minimize the changes on the customer side? Any suggestions are welcome.
Looks to me like the derived class for that member property violates Liskov's substitution principle.
You mentioned not being able to modify the Box class.
But are you allowed to modify the property base class? I suggest you add your "additional" methods of your derived class to the property base class.
The intent here being that the interface between the base and derived class should be one and the same. So do this only if it makes sense design wise.
In my simulation I have different objects that can be sensed in three ways: object can be seen and/or heard and/or smelled. For example, Animal can be seen, heard and smelled. And piece of Meat on the ground can be seen and smelled but not heard and Wall can only be seen. Then I have different sensors that gather this information - EyeSensor, EarSensor, NoseSensor.
Before state: brief version gist.github.com link
Before I started implementing NoseSensor I had all three functionality in one class that every object inherited - CanBeSensed because although classes were different they all needed the same getDistanceMethod() and if object implemented any CanBeSensed functionality it needed a senseMask - flags if object can be heard/seen/smelled and I didn't want to use virtual inheritance. I sacrificed having data members inside this class for smell, sounds, EyeInfo because objects that can only be seen do not need smell/sound info.
Objects then were registered in corresponding Sensor.
Now I've noticed that Smell and Sound sensors are the same and only differ in a single line inside a loop - one calls float getSound() and another float getSmell() on a CanBeSensed* object. When I create one of this two sensors I know what it needs to call, but I don't know how to choose that line without a condition and it's inside a tight loop and a virtual function.
So I've decided to make a single base class for these 3 functionality using virtual inheritance for base class with getDistanceMethod().
But now I had to make my SensorBase class a template class because of this method
virtual void sense(std::unordered_map<IdInt, CanBeSensed*>& objectsToSense) = 0;
, and it meant that I need to make SensorySubSystem class(manages sensors and objects in range) a template as well. And it meant that all my SubSystems like VisionSubSystem, HearingSubSystem and SmellSubSystem inherit from a template class, and it broke my SensorySystem class which was managing all SensorySubSystems through a vector of pointers to SensorySubSystem class std::vector<SensorySubSystem*> subSystems;
Please, could you suggest some solution for how to restructure this or how to make compiler decide at compile time(or at least decide once per call//once per object creation) what method to call inside Hearing/Smell Sensors.
Looking at your original design I have a few comments:
The class design in hierarchy.cpp looks quite ok to me.
Unless distance is something specific to sensory information getDistance() doesn't look like a method that belongs into this class. It could be moved either into a Vec2d-class or to a helper function (calculatePositon(vec2d, vec2d)). I do not see, why getDistance() is virtual, if it does something different than calculating the distance between the given position and the objects position, then it should be renamed.
The class CanBeSensed sounds more like a property and should probably be renamed to e.g. SensableObject.
Regarding your new approach:
Inheritance should primarily be used to express concepts (is-a-relations), not to share code. If you want to reuse an algorithm, consider writing an algorithm class or function (favour composition over inheritance).
In summary I propose to keep your original class design cleaning it up a little as described above. You could add virtual functions canBeSmelled/canBeHeard/canBeSeen to CanBeSensed.
Alternatively you could create a class hierachy:
class Object{ getPosition(); }
class ObjectWithSmell : virtual Object
class ObjectWithSound : virtual Object
...
But then you'd have to deal with virtual inheritance without any noticeable benefit.
The shared calculation code could go into an algorithmic class or function.
It might be already answered but it has bothered me a lot by giving me headaches so that's why I'm asking for a solution or an explanation.
The thing is that I'm developing a system in which I want to have only one properties(in terms of application) struct or sth accessible from everywhere in my code.
To give you the bigger plan I want to hold all my properties in an class object lets say Properties. So I decided to go with the Singleton on this one.
The point is that I want derived objects with their values and getter-setter methods coming from the base class Properties.
For example I want to have let's say two different objects from two different classes Component1Properties and Component2Properties. Now I want my Properties singleton to create a Components1Properties object and one Component2Properties object so that every-time I'm getting the same instance I'll have the same derived objects.
Now next let's add a static string "property" to each of the derived object and also declare a getter and setter method for this string.
The problem I'm facing is that I want from everywhere in my code to call the derived objects functions and get and set the values inside these objects
Example:
In my .h file:
class Properties
{
public:
static Properties& getInstance()
{
if instance==NULL} instance = new Properties();
return *instance;
}
private:
Properties();
static Properties* instance;
};
class Compoment1Properties : public Properties
{
public:
String property1;
void setProperty1(String value){
property1 = value;
}
String getValue(){
return property1
}
Component1Properties();
~Component1Properties(){};
};
Then in my .cpp file I have
Properties::Properties()
{
Component1Properties component1Properties;
}
I want from everywhere in the code to be able to get or set the values of the Component1Properties with something like:
String value = Properties::getInstance().component1Properties.getValue();
Properties::getInstance().component1Properties.setValue(value);
My questions here are
1. Is this feasible somehow ?
2. Is the architecture correct based on my needs ?
3. I'm I doing anything wrong ?
Thanks for your understanding and sorry if this is something to obvious but actually I'm trying to get familiarised with OOP principles in C++ but things are pretty messed up for me and I'm only getting headaches instead of results.
You can not have it working directly the way you want, simply because if you want to be able to have two objects Component1Properties and Component2Properties, both having Properties as a base class, then you will have at least two copies of Properties class: one in each component properties. This is just how inheritance works, but this clearly breaks your singleton approach.
What you can do is to have Component1Properties hold a reference (or, well, pointer) to a Properties object, and the same for Component2Properties. In this case it will be possible to share Properties object between component properties objects.
You can then have Properties object produce objects for particular components, most probably via some factory pattern, though I would suggest a separate class for this, like PropertiesFactory. It might as well be a singleton or even be contained in in Properties class, though even better might be main PropertiesManager class that is a factory producing global Properties as well as properties for each object.
Another approach that might be feasible if each component properties is just a subset of global properties. In such a case, you can have separate Component{1,2}Properties classes and Properties class that inherits all ComponentXProperties:
class Properties : public Component1Properties, Component2Properties {
};
In this case, you can just cast the global Properties object to any class you need. You may also try tricks with virtual inheritance here if your components have some properties in common, but overall this seems to be too complex and error-prone.
Registry Based Singletons
Use map of Pointers to base class in BASE class for storing objects and class name.
Use protected methods register and unregister in BASE class which accept BASE* and string name for derived class. register and unregister methods insert and remove objects from map, respect. CAREFUL with removal, as removing objects from does not mean invoking destructor!!
Add static lookup method to base class so as to check if object is in map.
3.In DERIVED class, constructors are private. for getInstance you need to do lookup first and if it returns no object, instantiate using private constructor and Register That object with Current derived class name.
I am working on a simple API in C++ where the end user of my code will pass an instance of a UserProfile class around to various other classes for modification. The user profile has a very basic public interface, with the data stored in a private pimpl object. I then add implementation classes as friends so they can access the internal data structure, which is defined in a separate implementation file. The basic outline of this class looks as follows . . .
// For pimpl here
class UserProfileData;
class UserProfile
{
public:
/// ctor to allocate impl
UserProfile();
/// dtor
~UserProfile();
/// Do some very simple stuff with a few methods
std::string getProfileName() const;
private:
/// Use pimpl and hide impl so API user can just use simplified interface
std::unique_ptr<UserProfileData> userProfileData;
/// Allow implementation classes access to userProfileData
friend class ClassOne;
friend class ClassTwo;
};
Building a big list of friend classes doesn't feel like the most elegant solution for hiding the data from the API user. It seems a little smelly. Are there any patterns or idioms that will allow me to achieve the same goal differently?
Think about what you're trying to achieve by hiding the implementation details of your UserProfile class. From the sounds of it, you're probably working to decouple consumers from the internal structure of the data. Doing this with the data container may be more trouble than it's worth, though.
Purely from the consumer's perspective, there's no need to hide the details of a class like this. Consider the following data types:
struct ProfileData
{
std::string profileName;
}
struct ProfileDataWithHiddenDetails
{
std::string getProfileName();
}
The purpose of each of these types is straightforward: they're used to transmit profile information between interested parties. Each type suits this purpose well, but one is much simpler to reason about than the other.
Does getProfileName communicate with a database? Does it retrieve the profile name from a deep hierarchy of values? Is the profile name just stored in a member variable? Any of these (among others) is possible; the information has been purposefully hidden from the consumer.
The first question is: Does this information need to be hidden from the consumer? If the consumer is using the object as a data container, then abstractions would only get in the way.
If your intent is to indeed hide details of the data structure, the next question is: What information do you need to hide from the consumer? If the object is not a simple data aggregator, consumers will need to adopt a different mindset when using it.
Abstractions can make it easier to reason about a system, but they can also make it harder. Try to abstract the behavior in your API rather than the data.
Example
Imagine ProfileDataWithHiddenDetails::getProfileName actually retrieves the profile name from a rich object model that you wanted to keep hidden from consumers. Something like:
std::string getProfileName
{
return objectModel.getRoot().getUserProfile().profileName;
}
These details don't need to be hidden in the implementation of getProfileName. Perhaps there was an API function call that returned the profile data:
ProfileDataWithHiddenDetails getProfileData()
{
return ProfileDataWithHiddenDetails(objectModel);
}
Instead of returning an abstraction, this API function could handle the abstraction itself:
ProfileData getProfileData()
{
auto profileName = objectModel.getRoot().getUserProfile().profileName;
return ProfileData { profileName };
}
Say I have two classes with different names but the exactly same structure. It there a way to cast an object of the one class to one of the other?
This might sound stupid to do but there is a reason why I want to do that. The architecture of my application provides the abstract classes component and storage The ready application will contain several specialized components derived from component and each of them will define its own storage type, derived from storage. During initialization of the application, for each component there will be a storage object of its custom storage type created and passed as pointer to the component.
This way all component stay completely independent which is great for re-usability and testing. But, of course, there is a need to exchange informations between components. To do that with independence in mind, I want to let two components get a storage pointer pointing to the same storage. The pointer by constraint must be of the component specific storage type.
framework code (abstract classes)
class Storage {};
class Component {
public:
void SetStorage(Storage* storage);
private:
Storage* storage;
};
example component
class PhysicsStorage : public Storage;
class PhysicsComponent : public Component;
another component
class CollisionStorage : public Storage; // same structure as PhysicsStorage as both components need the same data like world coordinates and rotations of all forms in the 3d space
class CollisionComponent : public Component;
main application
#include "system.h"
PhysicsStorage Worlddata;
PhysicsComponent Physics;
CollisionComponent Collision;
Physics.SetStorage(&Worlddata);
Collision.SetStorage(&Worlddata); // this points to a PhysicsStorage but that is actually the same like a CollisionStorage which is expected
So I wonder if there is a way of casting the pointer of say PhysicsStorage* to CollisionStorage*. In this case, both are defined in the file of their related component class. And both are derived from abstract Storage.
I only want to do that in the case that both custom storage types have exactly the same structure. Otherwise it would be senseless. I am not so familiar with advances pointer usage so I wonder if there is a way to do that. What I know is that you can cast to a base class, but this isn't what I want here. Using a shared storage type for two components would break independence. Thanks a lot!
This may work, and it may not. I believe this is a case of undefined behavior, and I would avoid doing this in production code.
Consider instead pushing the common fields and methods up into a new class and having ComponentOneStorage and ComponentTwoStorage inherit that class. Then you can pass around pointers/references to the base class instead, which will give you access to the common data without having to cast between incompatible pointer types.