OOP - Store objects and serve interfaces - c++

I'm currently working on a C++ project, I'm dealing with a home-made class CSound and handling its instances with a CSoundEngine, which allow myself to create a CSound (stored in my CSoundEngine) and return a pointer to it.
The fact is that I would like, for design purposes, to return a pointer to an interface. It is possible to store a real object in a vector for example, and serve it via an interface in C++ (or Java) ?
If the answer is yes, is it possible to store a vector a generic object which can be extended and return a specific interface depending on the child class ?
Thanks !

So, if I understand you correctly, you have something like:
class CSound {
// Whatever
};
class CSoundEngine {
// A lot of stuff
CSound* createSound(/* ... */);
};
And you don't want CSound be returned, but an interface, ALTHOUGH it is internally stored in a vector with it's specific type?
Well the first problem - Interface - is easy to solve:
Create your interfaces and derive from them.
class ISound {
public:
ISound(const ISound&) = delete;
ISound(ISound&&) = delete;
ISound& operator =(const ISound&) = delete;
ISound& operator =(ISound&&) = delete;
virtual ~ISound() = default;
// Your ISound public API here as pure virtual methods, e.g.:
virtual const std::string name() const = 0;
protected:
ISound() = default;
};
class ILoopable {
public:
ILoopable(const ILoopable&) = delete;
ILoopable(ILoopable&&) = delete;
ILoopable& operator =(const ILoopable&) = delete;
ILoopable& operator =(ILoopable&&) = delete;
virtual ~ILoopable() = default;
// Your ILoopable public API here as pure virtual methods, e.g.:
virtual const bool isLoopingActive() const = 0;
virtual bool setLoopingActive(bool) = 0;
protected:
ILoopable() = default;
};
class CDefaultSound
: public ISound {
public:
CDefaultSound () = default;
// ISound implementation
inline const std::string name() const { return mName; }
private:
std::string mName;
};
class CLoopableSound
: public ISound,
public ILoopable {
public:
CLoopableSound()
: ISound(),
ILoopable(),
mLoopingActive(true),
mName("")
{
}
// ISound implementation
inline const std::string name() const { return (mName + "(Loopable)"); }
// ILoopable implementation
inline const bool isLoopingActive() const { return mLoopingActive; }
inline bool setLoopingActive(bool active) { mLoopingActive = active; }
private:
bool mLoopingActive;
std::string mName;
};
int main()
{
// Now you can do something like this, for example, using polymorphism
// in your CSoundEngine (see below)...
ISound *pDef = new CDefaultSound();
ISound *pLoopable = new CLoopableSound();
}
If you want to use only CSound deriving from ISound that's fine, you don't need multiple classes, but then I don't understand the point of using an interface.
Important: Due to the pure virtual interface methods, you cannot instaniate the interface class, so you have to use a pointer or RAII-pointer like shared_ptr or unique_ptr (I'd recommend RAII anyway...)
The second problem - storing specific type in vector - is much harder, since you'd required a single vector foreach permitted type. OR! You store the interface-instances and only use the interface-methods!
class DefaultSoundCreator {
static ISound* createSound(/* Criteria */) { ... }
};
template <typename TSoundCreator>
class CSoundEngine {
public:
CSoundEngine()
: mSoundCreator() {
}
std::shared_ptr<ISound> createSound(/* some criteria */);
private:
std::vector<std::shared_ptr<ISound>> mSounds;
};
// cpp
std::shared_ptr<ISound> CSoundEngine::createSound(/* some criteria */) {
// Use criteria to create specific sound classes and store them in the mSOunds vector.
ISound *pSound = TSoundCreator::createSound(/* forward criteria for creation */);
std::shared_ptr<ISound> pSoundPtr = std::shared_ptr<ISound>(pSound);
mSounds.push_back(pSoundPtr);
return pSoundPtr;
}
int main() {
std::unique_ptr<CSoundEngine<DefaultSoundCreator>> pEngine = std::make_shared<CSoundEngine<DefaultSoundCreator>>();
std::shared_ptr<ISound> pSound = pEngine->createSound(/* Criteria */);
}
This way you could rely on the functionality provided by ISound, but by specifying the Creator-class, you could control sound-creation with a generic sound engine.
Now the actual problem of type-erasure using interface base classes: You known you stored a CLoopableSound at index 2 but you can only use ISound-Interfacemethods, due to the sound-engine's method createSound() : std::shared_ptr;
How do you access the ILoopable-behaviour?
And this is the point, where it becomes philosophical... I would recommend reading:
https://akrzemi1.wordpress.com/2013/11/18/type-erasure-part-i/
Type erasure techniques
https://aherrmann.github.io/programming/2014/10/19/type-erasure-with-merged-concepts/
One technique I like to use:
class CLoopableSound
: public ISound {
// All the above declarations and definitions
// AND:
static std::shared_ptr<CLoopableSound> fromISound(const std::shared_ptr<ISound>& other, bool *pSuccess = nullptr) {
std::shared_ptr<CLoopableSound> p = std::static_pointer_cast<CLoopableSound>(other);
if(pSuccess)
*pSuccess = p.operator bool();
return p;
}
};
// Use like
std::shared_ptr<CLoopableSound> pLoopable = CLoopableSound::fromISound(pSoundEngine->getSound(...));
if(pLoopable) {
// Use
}
Finally, you could of course make the fromISound-function a template and use the casts to access only ILoopable instead of CLoopableSound, etc..

Related

Implementing a ReaderWriter class based upon separate stateful Reader and Writer bases

Suppose I have two classes...
We can call the first FooReader and it looks something like this:
class FooReader {
public:
FooReader(const Foo* const foo)
: m_foo(foo) {
}
FooData readFooDataAndAdvance() {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
return m_foo[m_offset++];
}
private:
const Foo* const m_foo;
size_t m_offset = 0; // used in readFooDataAndAdvance
};
We can call the second FooWriter and it looks something like this:
class FooWriter {
public:
FooWriter(Foo* const foo)
: m_foo(foo) {
}
void writeFooDataAndAdvance(const FooData& foodata) {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
m_foo[m_offset++] = foodata;
}
private:
Foo* const m_foo;
size_t m_offset = 0;
};
These both work wonderfully and do their job as intended. Now suppose I want to create a FooReaderWriter class. Note that the
I naturally want to say that this new class "is a" FooReader and "is a" FooWriter; the interface is simply the amalgamation of the two classes and the semantics remain the same. I don't want to reimplement perfectly good member functions.
One could model this relationship using inheritance like so:
class FooReaderWriter : public FooReader, public FooWriter { };
This is nice because I get the shared interface, I get the implementation and I nicely model the relationship between the classes. However there are problems:
The Foo* member is duplicated in the base classes. This is a waste of memory.
The m_offset member is separate for each base type, but they need to share it (i.e. calling either readFooDataAndAdvance and writeFooDataAndAdvance should advance the same m_offset member).
I can't use the PIMPL pattern and store m_foo and m_offset in there, because I'd lose the const-ness of the m_foo pointer in the base FooReader class.
Is there anything else I can do to resolve these issues, without reimplementing the functionality contained within those classes?
This seems ready made for the mixin pattern. We have our most base class which just declares the members:
template <class T>
class members {
public:
members(T* f) : m_foo(f) { }
protected:
T* const m_foo;
size_t m_offset = 0;
};
and then we write some wrappers around it to add reading:
template <class T>
struct reader : T {
using T::T;
Foo readAndAdvance() {
return this->m_foo[this->m_offset++];
};
};
and writing:
template <class T>
struct writer : T {
using T::T;
void writeAndAdvance(Foo const& f) {
this->m_foo[this->m_offset++] = f;
}
};
and then you just use those as appropriate:
using FooReader = reader<members<Foo const>>;
using FooWriter = writer<members<Foo>>;
using FooReaderWriter = writer<reader<members<Foo>>>;
CRTP.
template<class Storage>
class FooReaderImpl {
public:
FooData readFooDataAndAdvance() {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
return get_storage()->m_foo[get_storage()->m_offset++];
}
private:
Storage const* get_storage() const { return static_cast<Storage const*>(this); }
Storage * get_storage() { return static_cast<Storage*>(this); }
};
template<class Storage>
class FooWriterImpl {
public:
void writeFooDataAndAdvance(const FooData& foodata) {
// the point here is that the algorithm is stateful
// and relies upon the m_offset member
get_storage()->m_foo[get_storage()->m_offset++] = foodata;
}
private:
Storage const* get_storage() const { return static_cast<Storage const*>(this); }
Storage * get_storage() { return static_cast<Storage*>(this); }
};
template<class T>
struct storage_with_offset {
T* m_foo = nullptr;
std::size_t m_offset = 0;
};
struct FooReader:
FooReaderImpl<FooReader>,
storage_with_offset<const Foo>
{
FooReader(Foo const* p):
storage_with_offset<const Foo>{p}
{}
};
struct FooWriter:
FooWriterImpl<FooWriter>,
storage_with_offset<Foo>
{
FooWriter(Foo* p):
storage_with_offset<Foo>{p}
{}
};
struct FooReaderWriter:
FooWriterImpl<FooReaderWriter>,
FooReaderImpl<FooReaderWriter>,
storage_with_offset<Foo>
{
FooReaderWriter(Foo const* p):
storage_with_offset<Foo>{p}
{}
};
If you need an abstract interface for runtime polymorphism, inherit FooReaderImpl and FooWriterImpl from them.
Now, FooReaderWriter obeys the ducktype contract of FooReader and FooWriter. So if you use type erasure instead of inheritance, it will qualify for either (at point of use).
I'd be tempted to change them to
using FooReader = std::function<FooData()>;
using FooWriter = std::function<void(FooData const&)>;
and then implement a multi-signature std::function for FooReaderWriter. But I'm strange and a bit unhinged that way.

C++ Overload an overrided method

Is it possible in C++ to overload in the child classes an overrided method?
I'm asking this because I have many child classes that although they are the same (in my case game objects) they interact in different ways with each others.
So, I need to create a function like void processCollision(GameObject obj) in the superclass.
But that could be overloaded in the child classes depending on the class of the GameObject (if it's a building, a car ...).
I'm just trying to run from the alternative which is using upcasting and RTTI.
What you're trying to implement is normally called "multiple dispatch" and unfortunately C++ doesn't support it directly (because in C++ view methods are bounded with classes and there are no multimethods).
Any C++ solution will require some coding for the implementation.
One simple symmetric way to implement it is to create a map for the supported cases:
typedef void (*Handler)(Obj *a, Obj *b);
typedef std::map<std::pair<OType, OType>, Handler> HandlerMap;
HandlerMap collision_handlers;
then the collision handling is:
HandlerMap::iterator i =
collision_handlers.find(std::make_pair(a->type, b->type));
if (i != collision_handlers.end()) i->second(a, b);
and the code goes in a free function.
If speed is a key factor and the object type can be coded in a small integer (e.g. 0...255) the dispatch could become for example:
collision_handlers[(a->type<<8)+b->type](a, b);
where collision handler is just an array of function pointers, and the speed should be equivalent to a single virtual dispatch.
The wikipedia link at the start of the answer lists another more sophisticated option for C++ (the visitor pattern).
"I'm just trying to run from the alternative which is using upcasting and RTTI."
Virtual polymorphism doesn't need upcasting or RTTI. Usually that's what virtual member functions are for:
class GameObject {
public:
virtual void processCollision(GameObject& obj);
};
class SomeGameObject1 : public GameObject {
public:
// SomeGameObject1's version of processCollision()
virtual void processCollision(GameObject& obj) {
// e.g here we also call the base class implementation
GameObject::processCollision();
// ... and add some additional operations
}
};
class SomeGameObject2 : public GameObject {
public:
// SomeGameObject2's version of processCollision()
virtual void processCollision(GameObject& obj) {
// Here we leave the base class implementation aside and do something
// completely different ...
}
};
MORE ADDITIONS AND THOUGHTS
As you're mentioning upcasting I'd suspect you want to handle collisions differently, depending on the actual GameObject type passed. This indeed would require upcasting (and thus RTTI) like follows
class Building : public GameObject {
public:
virtual void processCollision(GameObject& obj) {
Car* car = dynamic_cast<Car*>(&obj);
Airplane* airplane = dynamic_cast<Airplane*>(&obj);
if(car) {
car->crash();
}
else if(airplane) {
airplane->crash();
collapse();
}
void collapse();
};
Based on the above, that makes me contemplative about some design/architectural principles:
May be it's not the best idea to place the processCollision() implementation strategy to the GameObject classes themselves. These shouldn't know about each other (otherwise it will be tedious to introduce new GameObject types to the model)
You should introduce a kind of GameManager class that keeps track of moving/colliding GameObject instances, and chooses a GameObjectCollisionStrategy class implementing void processCollision(GameObject& a,GameObject& b); based on the actual types of a and b.
For choosing the strategy, and resolve the final GameObject implementations and corresponding strategies, you should concentrate all of that business knowdlege to a CollisionStrategyFactory, and delegate to this.
The latter would look something like this
class GameObjectCollisionStrategy {
public:
virtual processCollision(GameObject& a,GameObject& b) const = 0;
};
class CollideBuildingWithAirplane : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
Building* building = dynamic_cast<Building*>(a);
Airplane* airplane = dynamic_cast<Airplane*>(b);
if(building && airplane) {
airplane->crash();
building->collapse();
}
}
};
class CollideBuildingWithCar : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
Building* building = dynamic_cast<Building*>(a);
Car* car = dynamic_cast<Car*>(b);
if(building && car) {
car->crash();
}
}
};
class CollisionStrategyFactory {
public:
static const GameObjectCollisionStrategy& chooseStrategy
(GameObject* a, GameObject* b) {
if(dynamic_cast<Building*>(a)) {
if(dynamic_cast<Airplane*>(b)) {
return buildingAirplaneCollision;
}
else if(dynamic_cast<Car*>(b)) {
return buildingCarCollision;
}
}
return defaultCollisionStrategy;
}
private:
class DefaultCollisionStrategy : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
// Do nothing.
}
};
// Known strategies
static CollideBuildingWithAirplane buildingAirplaneCollision;
static CollideBuildingWithCar buildingCarCollision;
static DefaultCollisionStrategy defaultCollisionStrategy;
};
class GameManager {
public:
void processFrame(std::vector<GameObject*> gameObjects) {
for(std::vector<GameObject*>::iterator it1 = gameObjects.begin();
it1 != gameObjects.end();
++it1) {
for(std::vector<GameObject*>::iterator it2 = gameObjects.begin();
it2 != gameObjects.end();
++it2) {
if(*it1 == *it2) continue;
if(*it1->collides(*it2)) {
const GameObjectCollisionStrategy& strategy =
CollisionStrategyFactory::chooseStrategy(*it1,*it2);
strategy->processCollision(*(*it1),*(*it2));
}
}
}
}
};
Alternatively you may want to opt for static polymorphism, which also works without RTTI, but needs all types known at compile time. The basic pattern is the so called CRTP.
That should look as follows
class GameObject {
public:
// Put all the common attributes here
const Point& position() const;
const Area& area() const;
void move(const Vector& value);
};
template<class Derived>
class GameObjectBase : public GameObject {
public:
void processCollision(GameObject obj) {
static_cast<Derived*>(this)->processCollisionImpl(obj);
}
};
class SomeGameObject1 : public GameObjectBase<SomeGameObject1 > {
public:
// SomeGameObject1's version of processCollisionImpl()
void processCollisionImpl(GameObject obj) {
}
};
class SomeGameObject2 : public GameObjectBase<SomeGameObject2 > {
public:
// SomeGameObject2's version of processCollisionImpl()
void processCollisionImpl(GameObject obj) {
}
};
But this would unnecessarily complicate the design, and I doubt it will provide any benefits for your use case.

Overwrite Base Class Member with New Type

I'm trying to use C++ to emulate something like dynamic typing. I'm approaching the problem with inherited classes. For example, a function could be defined as
BaseClass* myFunction(int what) {
if (what == 1) {
return new DerivedClass1();
} else if (what == 2) {
return new DerivedClass2();
}
}
The base class and each derived class would have the same members, but of different types. For example, BaseClass may have int xyz = 0 (denoting nothing), DerivedClass1 might have double xyz = 123.456, and DerivedClass2 might have bool xyz = true. Then, I could create functions that returned one type but in reality returned several different types. The problem is, when ere I try to do this, I always access the base class's version of xyz. I've tried using pointers (void* for the base, and "correct" ones for the derived classes), but then every time I want to access the member, I have to do something like *(double*)(obj->xyz) which ends up being very messy and unreadable.
Here's an outline of my code:
#include <iostream>
using std::cout;
using std::endl;
class Foo {
public:
Foo() {};
void* member;
};
class Bar : public Foo {
public:
Bar() {
member = new double(123.456); // Make member a double
};
};
int main(int argc, char* args[]) {
Foo* obj = new Bar;
cout << *(double*)(obj->member);
return 0;
};
I guess what I'm trying to ask is, is this "good" coding practice? If not, is there a different approach to functions that return multiple types or accept multiple types?
That is not actually the way to do it.
There are two typical ways to implement something akin to dynamic typing in C++:
the Object-Oriented way: a class hierarchy and the Visitor pattern
the Functional-Programming way: a tagged union
The latter is rather simple using boost::variant, the former is well documented on the web. I would personally recommend boost::variant to start with.
If you want to go down the full dynamic typing road, then things get trickier. In dynamic typing, an object is generally represented as a dictionary containing both other objects and functions, and a function takes a list/dictionary of objects and returns a list/dictionary of objects. Modelling it in C++ is feasible, but it'll be wordy...
How is an object represented in a dynamically typed language ?
The more generic representation is for the language to represent an object as both a set of values (usually named) and a set of methods (named as well). A simplified representation looks like:
struct Object {
using ObjectPtr = std::shared_ptr<Object>;
using ObjectList = std::vector<ObjectPtr>;
using Method = std::function<ObjectList(ObjectList const&)>;
std::map<std::string, ObjectPtr> values;
std::map<std::string, Method> methods;
};
If we take Python as an example, we realize we are missing a couple things:
We cannot implement getattr for example, because ObjectPtr is a different type from Method
This is a recursive implementation, but without the basis: we are lacking innate types (typically Bool, Integer, String, ...)
Dealing with the first issue is relatively easy, we transform our object to be able to become callable:
class Object {
public:
using ObjectPtr = std::shared_ptr<Object>;
using ObjectList = std::vector<ObjectPtr>;
using Method = std::function<ObjectList(ObjectList const&)>;
virtual ~Object() {}
//
// Attributes
//
virtual bool hasattr(std::string const& name) {
throw std::runtime_error("hasattr not implemented");
}
virtual ObjectPtr getattr(std::string const&) {
throw std::runtime_error("gettattr not implemented");
}
virtual void setattr(std::string const&, ObjectPtr) {
throw std::runtime_error("settattr not implemented");
}
//
// Callable
//
virtual ObjectList call(ObjectList const&) {
throw std::runtime_error("call not implemented");
}
virtual void setcall(Method) {
throw std::runtime_error("setcall not implemented");
}
}; // class Object
class GenericObject: public Object {
public:
//
// Attributes
//
virtual bool hasattr(std::string const& name) override {
return values.count(name) > 0;
}
virtual ObjectPtr getattr(std::string const& name) override {
auto const it = values.find(name);
if (it == values.end) {
throw std::runtime_error("Unknown attribute");
}
return it->second;
}
virtual void setattr(std::string const& name, ObjectPtr object) override {
values[name] = std::move(object);
}
//
// Callable
//
virtual ObjectList call(ObjectList const& arguments) override {
if (not method) { throw std::runtime_error("call not implemented"); }
return method(arguments);
}
virtual void setcall(Method m) {
method = std::move(m);
}
private:
std::map<std::string, ObjectPtr> values;
Method method;
}; // class GenericObject
And dealing with the second issue requires seeding the recursion:
class BoolObject final: public Object {
public:
static BoolObject const True = BoolObject{true};
static BoolObject const False = BoolObject{false};
bool value;
}; // class BoolObject
class IntegerObject final: public Object {
public:
int value;
}; // class IntegerObject
class StringObject final: public Object {
public:
std::string value;
}; // class StringObject
And now you need to add capabilities, such as value comparison.
You can try the following design:
#include <iostream>
using std::cout;
using std::endl;
template<typename T>
class Foo {
public:
Foo() {};
virtual T& member() = 0;
};
class Bar : public Foo<double> {
public:
Bar() : member_(123.456) {
};
virtual double& member() { return member_; }
private:
double member_;
};
int main(int argc, char* args[]) {
Foo<double>* obj = new Bar;
cout << obj->member();
return 0;
};
But as a consequence the Foo class already needs to be specialized and isn't a container for any type anymore.
Other ways to do so, are e.g. using a boost::any in the base class
If you need a dynamic solution you should stick to using void* and size or boost::any. Also you need to pass around some type information as integer code or string so that you can decode the actual type of the content.
See also property design pattern.
For example, you can have a look at zeromq socket options https://github.com/zeromq/libzmq/blob/master/src/options.cpp

C++: Interface enforcing definition of copy-constr

Is there any way for an interface class to enforce a definition of the copy constructor and maybe of also other constructors? In my case, I have an IResource pure abstract class, and I want all classes that implement this interface to define a copy-constr, a constructor for loading from a file, and a constructor for loading from memory.
In order to construct an object, you need to know the concrete class to use (how would it otherwise know how much memory to allocate, or which virtual table to use, etc..?). As such, the interface is not in play when dealing with constructors, and you can't use interfaces (pure virtuals) to enforce the existence of such a constructor. It's kind of natural when you think about it, virtuals only work when you have a polymorphic object, i.e. after instantiation. Anyone referencing your IResource interface would only ever deal with instantiated objects, and never touch a constructor.
You can enforce these kind of constraints on stuff using templates if you want though. By simply calling the copy constructor from a templated function, the compiler will complain if it encounters a template instantiation using a type which does not have a copy constructor.
You cannot enforce that and it would not be a right way either. On the contrary, you should prevent the usage of public copy constructors in a polymorphic class hierarchy...
struct IResource {
virtual IResource* Clone() const = 0;
virtual ~IResource() {}
};
An implementer of IResource should follow this pattern:
class ConcreteResource : public IResource, public boost::noncopyable { // or equivalent
public:
virtual ConcreteResource* Clone() const;
explicit ConcreteResource(std::string const & pString) : mString(pString) {}
private:
std::string mString;
};
ConcreteResource* ConcreteResource::Clone() const {
return new ConcreteResource(this->mString);
}
Something in your project uses the IResource abstract class and somehow I doubt that it requires that the objects it uses contain particular constructors.
Something else creates IResource objects (possibly lots of things) and to do that it must use a constructor. The concrete classes that get created must implement the necessary constructors or the code will not compile.
So the answer to your question is that you enforce the presence of the constructors by using those constructors in some other code to create objects. Keep in mind, if the constructors aren't being used anywhere, they aren't necessary.
you can push all requirements to the resource implementations like so:
class t_resource_interface {
protected:
virtual ~t_resource_interface();
public:
virtual t_serialization* serializeResource() = 0;
virtual t_thing* cloneResource() = 0;
};
/* type disambiguators */
typedef enum t_load_from_url { LoadFromURL = 0 } t_load_from_url;
typedef enum t_load_from_memory { LoadFromMemory = 0 } t_load_from_memory;
typedef enum t_copy_constructor { CopyConstructor = 0 } t_copy_constructor;
template < typename TResourceImplementation >
class t_resource : public t_resource_interface {
public:
/* copy ctor should generally be avoided due to the expense. introduce a parameter for those cases where it's really needed and disable the standard copy ctor */
t_resource(const t_copy_constructor& copyCtor, const t_resource& other) : t_resource_interface(), d_implementation(TResourceImplementation::CopyConstructor(other.d_implementation)) {
MONUnusedParameter(copyCtor);
}
t_resource(const t_load_from_url& fromFile, const t_url& url) : t_resource_interface(), d_implementation(TResourceImplementation::LoadFromURL(url)) {
MONUnusedParameter(fromFile);
}
t_resource(const t_load_from_memory& fromMemory, const t_serialization& serialization) : t_resource_interface(), d_implementation(TResourceImplementation::LoadFromMemory(serialization)) {
MONUnusedParameter(fromMemory);
}
virtual ~t_resource() {
}
public:
/* t_resource_interface requirements. implementation forwarded to TResourceImplementation */
virtual t_serialization* serializeResource() {
return this->d_implementation->serializeResource();
}
virtual t_thing* cloneResource() {
return this->d_implementation->cloneResource();
}
private:
/* assuming you will end up needing dynamic allocation/polymorphism along the way... */
t_auto_pointer<TResourceImplementation> d_implementation;
private:
/* prohibited */
t_resource(const t_resource&);
t_resource& operator=(const t_resource&);
};
class t_image_resource_implementation : public t_resource_interface {
private:
static t_image_resource_implementation* ValidationCheck(const t_image_resource_implementation* const arg) {
assert(arg && "allocation or argument error");
if (0 == arg) {
return 0;
}
else if (0 == arg->isValid()) {
delete res;
return 0;
}
else {
return arg;
}
}
public:
static t_image_resource_implementation* CopyConstructor(const t_image_resource_implementation* const other) {
return ValidationCheck(new t_image_resource_implementation(other, ...));
}
static t_image_resource_implementation* LoadFromURL(const t_url& url) {
/* assuming t_image_at_url_resource_implementation exists */
return ValidationCheck(new t_image_at_url_resource_implementation(url, ...));
}
static t_image_resource_implementation* LoadFromMemory(const t_serialization& serialization) {
assert(serialization);
if (0 == serialization) {
return 0;
}
else {
return ValidationCheck(new t_image_resource_implementation(serialization, ...));
}
}
/* some physical ctors and the rest of the implementation... */
public:
/* t_resource_interface requirements */
virtual t_serialization* serializeResource() {
return this->createSerialization();
}
virtual t_thing* cloneResource() {
return this->clone();
}
};
typedef t_resource<t_image_resource_implementation> t_image_resource;
t_error_code ConvertImageToGrayscale(const t_url& sourceUrl, const t_url& destinationUrl) {
t_image_resource imageResource(LoadFromURL, sourceUrl);
/* ... */
}

minimal reflection in C++

I want to create a class factory and I would like to use reflection for that. I just need to
create a object with given string and invoke only few known methods.
How i can do that?
You will have to roll your own. Usually you have a map of strings to object creation functions.
You will need something like the follwing:
class thing {...};
/*
class thing_A : public thing {...};
class thing_B : public thing {...};
class thing_C : public thing {...};
*/
std::shared_ptr<thing> create_thing_A();
std::shared_ptr<thing> create_thing_C();
std::shared_ptr<thing> create_thing_D();
namespace {
typedef std::shared_ptr<thing> (*create_func)();
typedef std::map<std::string,create_func> creation_map;
typedef creation_map::value_type creation_map_entry;
const creation_map_entry creation_map_entries[] = { {"A", create_thing_A}
, {"B", create_thing_B}
, {"C", create_thing_C} };
const creation_map creation_funcs(
creation_map_entries,
creation_map_entries + sizeof(creation_map_entries)
/ sizeof(creation_map_entries[0] );
}
std::shared_ptr<thing> create_thing(const std::string& type)
{
const creation_ma::const_iterator it = creation_map.find(type);
if( it == creation_map.end() ) {
throw "Dooh!"; // or return NULL or whatever suits you
}
return it->second();
}
There are other ways to do this (like having a map of strings to objects from which to clone), but I think they all boil down to having a map of strings to something related to the specific types.
There is no reflection in C++, directly supported by the standard.
However C++ is sufficiently low-level that you can implement some minimal support for reflection to complete the task at hand.
For the simple task of creating a Factory, you usually use the Prototype approach:
class Base
{
public:
virtual Base* clone() const = 0;
virtual ~Base();
};
class Factory
{
public:
std::unique_ptr<Base> get(std::string const& name);
void set(std::string const& name, std::unique_ptr<Base> b);
private:
boost::ptr_map<std::string,Base> mExemplars;
};
Of course, those "known methods" that you are speaking about should be defined within the Base class, which acts as an interface.
There is no reflection in C++, so you should restate your question trying to explain what are the requirements that you would have fulfilled with the reflection part of it.
Depending on your actual constraints and requirements, there are a few things that you can do. The first approach that I would take would be creating an abstract factory where concrete factories can register and provide a simple interface:
class Base {}; // shared base by all created objects
class ConcreteFactoryBase {
public:
virtual ~ConcreteFactoryBase() {}
virtual Base* create() const = 0; // actual construction
virtual std::string id() const = 0; // id of the types returned
};
class AbstractFactory
{
typedef std::map<std::string, ConcreteFactory* > factory_map_t;
public:
void registerFactory( ConcreteFactoryBase* factory ) {
factories[ factory->id() ] = factory;
}
Base* create( std::string const & id ) const {
factory_map_t::const_iterator it = factories.find( id );
if ( it == factories.end() ) {
return 0; // or throw, or whatever makes sense in your case
}
return (*it)->create();
}
~AbstractFactory(); // ensure that the concrete factories are deleted
private:
std::map<ConcreteFactoryBase*> factories;
};
The actual concrete factories can be implemented manually but they can probably be templated, unless the constructors for the different types require different arguments:
template <typename T>
class ConcreteFactory : public ConcreteFactoryBase {
public:
ConcreteFactory( std::string const & id ) : myid(id) {}
virtual Base* create() const {
return new T;
}
virtual std::string id() const {
return myid;
}
private:
std::string myid;
};
class Test : public Base {};
int main() {
AbstracFactory factory;
factory.register_factory( new ConcreteFactory<Test>("Test") );
}
Optionally you could adapt the signatures so that you can pass arguments to the constructor through the different layers.
Then again, by knowing the actual constraints some other approaches might be better. The clone() approach suggested elsewhere is good (either by actually cloning or by creating an empty object of the same type). That is basically blending the factory with the objects themselves so that each object is a factory of objects of the same type. I don't quite like mixing those two responsabilities but it might be one of the simplest approaches with less code to write.
You could use typeid & templates to implement the factory so you won't need strings at all.
#include <string>
#include <map>
#include <typeinfo>
//***** Base *****
class Base
{
public:
virtual ~Base(){} //needs to be virtual to make typeid work
};
//***** C1 *****
class C1 : public Base
{};
//***** Factory *****
class Factory
{
public:
template <class T>
Base& get();
private:
typedef std::map<std::string, Base> BaseMap;
BaseMap m_Instances;
};
template <class T>
Base& Factory::get()
{
BaseMap::const_iterator i = m_Instances.find(typeid(T).name());
if(i == m_Instances.end()) {
m_Instances[typeid(T).name()] = T();
}
return m_Instances[typeid(T).name()];
}
//***** main *****
int main(int argc, char *argv[])
{
Factory f;
Base& c1 = f.get<C1>();
return 0;
}