I have a design question that has been bugging me for a while but I cannot find a good (in a OOP sense) solution for this. The language is C++ and I keep coming back to RTTI - which is often referred to as an indicator for bad design.
Suppose we have a set of different kinds of modules implemented as different classes. Each kind of module is characterized by a defined interface, however the implementation may vary.
Thus my first idea was to create an interface (pure abstract) class for each kind of module (e.g. IModuleFoo, IModuleBar etc.) and the implementations in seperate classes. So far so good.
class IModuleFoo {
public:
virtual void doFoo() = 0;
};
class IModuleBar {
public:
virtual void doBar() = 0;
};
On the other hand we have a set of (application) classes and each of them uses a couple of those modules but only through the interfaces - even the modules themselves might use other modules. However, all of the application classes will share the same pool of modules. My idea was to create a manager class (ModuleManager) for all modules which application classes can query for the module types they need. The available modules (and the concrete implementation) are set up during initialization of the manager and may vary over time (but that is not really part of my question).
Since the number of different module kinds is most probably >10 and may increase over time it does not appear suitable to me to store references (or pointers) to them separately. In addition there might be a couple of functions the manager needs to invoke on all managed modules. Thus I created another interface (IManagedModule) with the benefit that I can now use a container (list, set, whatsoever) of IManagedModules to store them in the manager.
class IManagedModule {
public:
virtual void connect() = 0;
{ ... }
};
The consequence is that a module that shall be managed needs to inherit both from the IManagedModule and from the appropriate interface for its type.
But things turn ugly when I think about the ModuleManager. It can be assumed that there is at most one instance of each module type present at each time. Thus if it was possible to do something like this (where manager is the instance of the ModuleManager), everything would be fine:
IModuleFoo* pFoo = manager.get(IModuleFoo);
But I'm pretty sure that it's not. I also thought about a template based solution like:
IModuleFoo* pFoo = manager.get<IModuleFoo>();
That could work but I have no idea how to find the right module within the manager if all I have is a set of IManagedModules - that is without the use of RTTI, of course.
One approach would be to provide IManagedModule with a virtual getId() method, rely on the implementations to use non-ambigous ids for each kind of module and do the pointer casting on your own. But that's just reinventing the wheel (namely RTTI) and requires a lot of discipline within the implementing classes (providing the right ids etc...) which is not desirable.
Long story short - the question is if there is really no way around some kind of RTTI here and in this case RTTI might even be a valid solution or if there might be a better (cleaner, safer, ...) design which exhibits the same flexibility (e.g. loose coupling between application classes and module classes...)? Did I miss anything?
It sounds like you're looking for something similar to COM's QueryInterface. Now, you don't need to implement COM entirely, but the basic principle stands: You have a base class, with a virtual function, to which you pass an identifier specifying which interface you want. The virtual function then looks to see if it can implement that interface, and if so, passes back a pointer to that interface.
For example:
struct IModuleBase {
// names changed so as not to confuse later programmers with true COM
virtual bool LookupInterface(int InterfaceID, void **interfacePtr) = 0;
// Easy template wrapper
template<typename Interface>
Interface *LookupInterface() {
void *ptr;
if (!LookupInterface(Interface::INTERFACE_ID, &ptr)) return NULL;
return (Interface *)ptr;
}
};
struct IModuleFoo : public IModuleBase {
enum { INTERFACE_ID = 42 };
virtual void foo() = 0;
};
struct SomeModule : public IModuleFoo {
virtual bool LookupInterface(int interface_id, void **pPtr) {
switch (interface_id) {
case IModuleFoo::INTERFACE_ID:
*pPtr = (void*)static_cast<IModuleFoo *>(this);
return true;
default:
return false;
}
}
virtual void foo() { /* ... */ }
};
It's a bit unwieldy, but it's not too bad, and without RTTI you don't have much of a choice besides an approach like this.
I think bdonlan's suggestion is good, but requiring each module type to declare a distinct INTERFACE_ID is a maintenance headache. The distinctness can be accomplished automatically by having each module type declare a static object and using its address as the ID:
struct IModuleFoo : public IModuleBase {
static char distinct_; // Exists only to occupy a unique address
static const void *INTERFACE_ID;
virtual void foo() = 0;
};
// static members need separate out-of-class definitions
char IModuleFoo::distinct_;
const void *IModuleFoo::INTERFACE_ID = &distinct_;
In this case we are using void * as the interface ID type, instead of int or an enumerated type, so the types in some other declarations will need to change.
Also, due to quirks in C++, the INTERFACE_ID values, despite being labelled const, are not "constant enough" to be used for case labels in switch statements (or array size declarations, or a handful of other places), so you would need to change the switch statement to an if. As described in section 5.19 of the standard, a case label requires an integral constant-expression, which roughly speaking is something the compiler can determine just from looking at the current translation unit; while INTERFACE_ID is a mere constant-expression, whose value cannot be determined until link time.
Related
We can overload functions by giving them a different number of parameters. For example, functions someFunc() and someFunc(int i) can do completely different things.
Is it possible to achieve the same effect on classes? For example, having one class name but creating one class if a function is not called and a different class if that function is not called. For example, If I have a dataStorage class, I want the internal implementation to be a list if only add is called, but want it to be a heap if both add and pop are called.
I am trying to implement this in C++, but I am curious if this is even possible. Examples in other languages would also help. Thanks!
The type of an object must be completely known at the point of definition. The type cannot depend on what is done with the object later.
For the dataStorage example, you could define dataStorage as an abstract class. For example:
struct dataStorage {
virtual ~dataStorage() = default;
virtual void add(dataType data) = 0;
// And anything else necessarily common to all implementations.
};
There could be a "default" implementation that uses a list.
struct dataList : public dataStorage {
void add(dataType data) override;
// And whatever else is needed.
};
There could be another implementation that uses a heap.
struct dataHeap : public dataStorage {
void add(dataType data) override;
void pop(); // Maybe return `dataType`, if desired
// And whatever else is needed.
};
Functions that need only to add data would work on references to dataStorage. Functions that need to pop data would work on references to dataHeap. When you define an object, you would choose dataList if the compiler allows it, dataHeap otherwise. (The compiler would not allow passing a dataList object to a function that requires a dataHeap&.) This is similar to what you asked for, except it does require manual intervention. On the bright side, you can use the compiler to tell you which decision to make.
A downside of this approach is that changes can get messy. There is additional maintenance and runtime overhead compared to simply always using a heap (one class, no inheritance). You should do some performance measurements to ensure that the cost is worth it. Sometimes simplicity is the best design, even if it is not optimal in all cases.
Problem
I would like to detect if a class has member variables and fail a static assert if they do. Something like:
struct b {
int a;
}
static_assert(!has_member_variables<b>, "Class should not contain members"). // Error.
struct c {
virtual void a() {}
void other() {}
}
static_assert(!has_member_variables<c>, "Class should not contain members"). // Fine.
struct d : c {
}
static_assert(!has_member_variables<d>, "Class should not contain members"). // Fine.
struct e : b {
}
static_assert(!has_member_variables<e>, "Class should not contain members"). // Error.
struct f : c {
char z;
}
static_assert(!has_member_variables<f>, "Class should not contain members"). // Error.
Is there a way to achieve this with SFINAE template? This class may have inheritance or even multiple inheritance with virtual functions (no members in the base classes though).
Motivation
I have a pretty simple setup as follows:
class iFuncRtn {
virtual Status runFunc(Data &data) = 0;
};
template <TRoutine, TSpecialDataType>
class FuncRoutineDataHelper : public iFuncRtn {
Status runFunc(Data &data) {
static_assert(!has_member_variables<TRoutine>, "Routines shouldnt have data members!");
// Prepare special data for routine
TSpecialDataType sData(data);
runFuncImpl(sData);
}
class SpecificRtn :
public FuncRoutineDataHelper<SpecificRtn, MySpecialData> {
virtual Status runFuncImpl(MySpecialData &sData) {
// Calculate based on input
sData.setValue(someCalculation);
}
};
The FunctionalityRoutines are managed and run on a per tick basis. They are customized and can perform a wide variety of tasks such as contacting other devices etc. The data that is passed in can be manipulated by the routine and is guaranteed to be passed in on each tick execution until the functionality is finished. The right type of data is passed in based on the DataHelper class. I wan't to discourage future people from mistakenly adding data to the functionality routines as it is very unlikely to do what they expect. To force this, I was hoping to find a way with static assert.
You can solve this by depending on the compiler doing empty base class optimizations, by checking if a class derived from your T has the same size as an empty class with virtual functions:
template<typename T, typename... BaseClasses>
class IsEmpty
{
// sanity check; see the updated demo below
static_assert(IsDerivedFrom<T, BaseClasses...>::value);
struct NonDerived : BaseClasses... { virtual ~NonDerived() = default; };
struct Derived : T { virtual ~Derived() = default; };
public:
inline static constexpr bool value = (sizeof(NonDerived) == sizeof(Derived));
};
This should work with both single and multiple inheritance. However, when using multiple inheritance, it's necessary to list all base classes, like that:
static_assert(IsEmpty<Derived, Base1, Base2, Base3>::value);
Obviously, this solution rules out final classes.
Here's the updated demo.
Here's the original demo. (doesn't work with multiple inheritance)
You will have to mark the classes in some way or another. Pick a way you are comfortable with, a property or some kind of type integer member with an enum. Whoever makes sub-classes will have to follow your convention to make it work.
All other answers here will be some variant of this.
Any answer that uses a sizeof could not guarantee this will work between platforms, compilers, or even classes on the same platform and compiler, due to easily being able to fit a new member inside the default class member alignment, where the sizes of sizeof could easily end up the same for a sub-class.
Background:
As stated in your code and question, all of that is just plain and basic C ad C++ code, and is resolved entirely at compile time. The compiler will tell you if a member exists or not. After its compiled it's a mash of efficient, nameless, machine code with no hints or help for that kind of thing by itself.
Any name you use for a function or data member effectively disappears, as you know it and see it there, after compile and there is no way to lookup any member by name. Each data member is known only by its numerical offset from the top of the class or struct.
Systems like .Net, Java, and others are designed for reflection, which is the ability to remember class members by name, where you can find them at runtime when you program is running.
Templates in C++, unless mixed mode C++ on something like .Net, are also all resolved at compile time, and the names will also all be gone, so the templates by themselves buy you nothing.
Languages like Objective-C also are written to not fail necessarily if certain types of special members are missing, similar to what you are asking, but under the covers its using a lot of supporting code and runtime management to keep track independently, where the actual function itself and its code are still unware and rely on other code to tell them if a member exists or to not fail on null member.
In pure C or C++ you will need to just make your own system, and be literal about tracking dynamically what does what. You could make enums, or lists or dictionaries of name strings. This is what is normally done, you just have to leave hints for yourself. A class cannot be compiled in a way that gives implicit visibility to future sub-classes by definition, without using some form if RTTI.
Its common to put a type member on a class for this very reason, which could be a simple enum. I would not count on sizes or anything that might be platform dependent.
I'm in a situation where I have a class, let's call it Generic. This class has members and attributes, and I plan to use it in a std::vector<Generic> or similar, processing several instances of this class.
Also, I want to specialize this class, the only difference between the generic and specialized objects would be a private method, which does not access any member of the class (but is called by other methods). My first idea was to simply declare it virtual and overload it in specialized classes like this:
class Generic
{
// all other members and attributes
private:
virtual float specialFunc(float x) const =0;
};
class Specialized_one : public Generic
{
private:
virtual float specialFunc(float x) const{ return x;}
};
class Specialized_two : public Generic
{
private:
virtual float specialFunc(float x) const{ return 2*x; }
}
And thus I guess I would have to use a std::vector<Generic*>, and create and destroy the objects dynamically.
A friend suggested me using a std::function<> attribute for my Generic class, and give the specialFunc as an argument to the constructor but I am not sure how to do it properly.
What would be the advantages and drawbacks of these two approaches, and are there other (better ?) ways to do the same thing ? I'm quite curious about it.
For the details, the specialization of each object I instantiate would be determined at runtime, depending on user input. And I might end up with a lot of these objects (not yet sure how many), so I would like to avoid any unnecessary overhead.
virtual functions and overloading model an is-a relationship while std::function models a has-a relationship.
Which one to use depends on your specific use case.
Using std::function is perhaps more flexible as you can easily modify the functionality without introducing new types.
Performance should not be the main decision point here unless this code is provably (i.e. you measured it) the tight loop bottleneck in your program.
First of all, let's throw performance out the window.
If you use virtual functions, as you stated, you may end up with a lot of classes with the same interface:
class generic {
virtual f(float x);
};
class spec1 : public generic {
virtual f(float x);
};
class spec2 : public generic {
virtual f(float x);
};
Using std::function<void(float)> as a member would allow you to avoid all the specializations:
class meaningful_class_name {
std::function<void(float)> f;
public:
meaningful_class_name(std::function<void(float)> const& p_f) : f(p_f) {}
};
In fact, if this is the ONLY thing you're using the class for, you might as well just remove it, and use a std::function<void(float)> at the level of the caller.
Advantages of std::function:
1) Less code (1 class for N functions, whereas the virtual method requires N classes for N functions. I'm making the assumption that this function is the only thing that's going to differ between classes).
2) Much more flexibility (You can pass in capturing lambdas that hold state if you want to).
3) If you write the class as a template, you could use it for all kinds of function signatures if needed.
Using std::function solves whatever problem you're attempting to tackle with virtual functions, and it seems to do it better. However, I'm not going to assert that std::function will always be better than a bunch of virtual functions in several classes. Sometimes, these functions have to be private and virtual because their implementation has nothing to do with any outside callers, so flexibility is NOT an advantage.
Disadvantages of std::function:
1) I was about to write that you can't access the private members of the generic class, but then I realized that you can modify the std::function in the class itself with a capturing lambda that holds this. Given the way you outlined the class however, this shouldn't be a problem since it seems to be oblivious to any sort of internal state.
What would be the advantages and drawbacks of these two approaches, and are there other (better ?) ways to do the same thing ?
The issue I can see is "how do you want your class defined?" (as in, what is the public interface?)
Consider creating an API like this:
class Generic
{
// all other members and attributes
explicit Generic(std::function<float(float)> specialFunc);
};
Now, you can create any instance of Generic, without care. If you have no idea what you will place in specialFunc, this is the best alternative ("you have no idea" means that clients of your code may decide in one month to place a function from another library there, an identical function ("receive x, return x"), accessing some database for the value, passing a stateful functor into your function, or whatever else).
Also, if the specialFunc can change for an existing instance (i.e. create instance with specialFunc, use it, change specialFunc, use it again, etc) you should use this variant.
This variant may be imposed on your code base by other constraints. (for example, if want to avoid making Generic virtual, or if you need it to be final for other reasons).
If (on the other hand) your specialFunc can only be a choice from a limited number of implementations, and client code cannot decide later they want something else - i.e. you only have identical function and doubling the value - like in your example - then you should rely on specializations, like in the code in your question.
TLDR: Decide based on the usage scenarios of your class.
Edit: regarding beter (or at least alternative) ways to do this ... You could inject the specialFunc in your class on an "per needed" basis:
That is, instead of this:
class Generic
{
public:
Generic(std::function<float(float> f) : specialFunc{f} {}
void fancy_computation2() { 2 * specialFunc(2.); }
void fancy_computation4() { 4 * specialFunc(4.); }
private:
std::function<float(float> specialFunc;
};
You could write this:
class Generic
{
public:
Generic() {}
void fancy_computation2(std::function<float(float> f) { 2 * f(2.); }
void fancy_computation4(std::function<float(float> f) { 4 * f(4.); }
private:
};
This offers you more flexibility (you can use different special functions with single instance), at the cost of more complicated client code. This may also be a level of flexibility that you do not want (too much).
I am wrapping a library which I did not write to make it more user friendly. There are a huge number of functions which are very basic so it's not ideal to have to wrap all of these when all that is really required is type conversion of the results.
A contrived example:
Say the library has a class QueryService, it has among others this method:
WeirdInt getId() const;
I'd like a standard int in my interface however, I can get an int out of WeirdInt no problem as I know how to do this. In this case lets say that WeirdInt has:
int getValue() const;
This is a very simple example, often the type conversion is more complicated and not always just a call to getValue().
There are literally hundreds of function calls that return types likes these and more are added all the time, so I'd like to try and reduce the burden on myself having to constantly add a bajillion methods every time the library does just to turn WeirdType into type.
I want to end up with a QueryServiceWrapper which has all the same functionality as QueryService, but where I've converted the types. Am I going to have to write an identically names method to wrap every method in QueryService? Or is there some magic I'm missing? There is a bit more to it as well, but not relevant to this question.
Thanks
The first approach I'd think is by trying with templates such that
you provide a standard implementation for all the wrapper types which have a trivial getValue() method
you specialize the template for all the others
Something like:
class WeirdInt
{
int v;
public:
WeirdInt(int v) : v(v) { }
int getValue() { return v; }
};
class ComplexInt
{
int v;
public:
ComplexInt(int v) : v(v) { }
int getValue() { return v; }
};
template<typename A, typename B>
A wrap(B type)
{
return type.getValue();
}
template<>
int wrap(ComplexInt type)
{
int v = type.getValue();
return v*2;
};
int x = wrap<int, WeirdInt>(WeirdInt(5));
int y = wrap<int, ComplexInt>(ComplexInt(10));
If the wrapper methods for QueryService have a simple pattern, you could also think of generating QueryServiceWrapper with some perl or python script, using some heuristics. Then you need to define some input parameters at most.
Even defining some macros would help in writing this wrapper class.
Briefly, If your aim is to encapsulate the functionality completely so that WeirdInt and QueryService are not exposed to the 'client' code such that you don't need to include any headers which declare them in the client code, then I doubt the approach you take will be able to benefit from any magic.
When I've done this before, my first step has been to use the pimpl idiom so that your header contains no implementation details as follows:
QueryServiceWrapper.h
class QueryServiceWrapperImpl;
class QueryServiceWrapper
{
public:
QueryServiceWrapper();
virtual ~QueryServiceWrapper();
int getId();
private:
QueryServiceWrapperImpl impl_;
};
and then in the definition, you can put the implementation details, safe in the knowledge that it will not leach out to any downstream code:
QueryServiceWrapper.cpp
struct QueryServiceWrapperImpl
{
public:
QueryService svc_;
};
// ...
int QueryServiceWrapper::getValue()
{
return impl_->svc_.getId().getValue();
}
Without knowing what different methods need to be employed to do the conversion, it's difficult add too much more here, but you could certainly use template functions to do conversion of the most popular types.
The downside here is that you'd have to implement everything yourself. This could be a double edged sword as it's then possible to implement only that functionality that you really need. There's generally no point in wrapping functionality that is never used.
I don't know of a 'silver bullet' that will implement the functions - or even empty wrappers on the functions. I've normally done this by a combination of shell scripts to either create the empty classes that I want or taking a copy of the header and using text manipulation using sed or Perl to change original types to the new types for the wrapper class.
It's tempting in these cases to use public inheritance to enable access to the base functions while allowing functions to be overridden. However, this is not applicable in your case as you want to change return types (not sufficient for an overload) and (presumably) you want to prevent exposure of the original Weird types.
The way forward here has to be to use aggregation although in such as case there is no way you can easily avoid re-implementing (some of) the interfaces unless you are prepared to automate the creation of the class (using code generation) to some extent.
more complex approach is to introduce a required number of facade classes over original QueryService, each of which has a limited set of functions for one particular query or query-type. I don't know that your particular QueryService do, so here is an imaginary example:
suppose the original class have a lot of weired methods worked with strange types
struct OriginQueryService
{
WeirdType1 query_for_smth(...);
WeirdType1 smth_related(...);
WeirdType2 another_query(...);
void smth_related_to_another_query(...);
// and so on (a lot of other function-members)
};
then you may write some facade classes like this:
struct QueryFacade
{
OriginQueryService& m_instance;
QueryFacade(OriginQueryService* qs) : m_instance(*qs) {}
// Wrap original query_for_smth(), possible w/ changed type of
// parameters (if you'd like to convert 'em from C++ native types to
// some WeirdTypeX)...
DesiredType1 query_for_smth(...);
// more wrappers related to this particular query/task
DesiredType1 smth_related(...);
};
struct AnotherQueryFacade
{
OriginQueryService& m_instance;
AnotherQueryFacade(OriginQueryService* qs) : m_instance(*qs) {}
DesiredType2 another_query(...);
void smth_related_to_another_query(...);
};
every method delegate call to m_instance and decorated w/ input/output types conversion in a way you want it. Types conversion can be implemented as #Jack describe in his post. Or you can provide a set of free functions in your namespace (like Desired fromWeird(const Weired&); and Weired toWeired(const Desired&);) which would be choosen by ADL, so if some new type arise, all that you have to do is to provide overloads for this 2 functions... such approach work quite well in boost::serialization.
Also you may provide a generic (template) version for that functions, which would call getValue() for example, in case if lot of your Weired types has such member.
I'm building an hierarchy of objects that wrap primitive types, e.g integers, booleans, floats etc, as well as container types like vectors, maps and sets. I'm trying to (be able to) build an arbitrary hierarchy of objects, and be able to set/get their values with ease. This hierarchy will be passed to another class (not mentioned here) and an interface will be created from this representation. This is the purpose of this hierarchy, to be able to create a GUI representation from these objects.To be more precise, i have something like this:
class ValObject
{
public:
virtual ~ValObject() {}
};
class Int : public ValObject
{
public:
Int(int v) : val(v) {}
void set_int(int v) { val = v);
int get_int() const { return val; }
private:
int val;
};
// other classes for floats, booleans, strings, etc
// ...
class Map : public ValObject {}
{
public:
void set_val_for_key(const string& key, ValObject* val);
ValObject* val_for_key(const string& key);
private:
map<string, ValObject*> keyvals;
};
// classes for other containers (vector and set) ...
The client, should be able to create and arbitrary hierarchy of objects, set and get their values with ease, and I, as a junior programmer, should learn how to correctly create the classes for something like this.
The main problem I'm facing is how to set/get the values through a pointer to the base class ValObject. At first, i thought i could just create lots of functions in the base class, like set_int, get_int, set_string, get_string, set_value_for_key, get_value_for_key, etc, and make them work only for the correct types. But then, i would have lots of cases where functions do nothing and just pollute my interface. My second thought was to create various proxy objects for setting and getting the various values, e.g
class ValObject
{
public:
virtual ~ValObject() {}
virtual IntProxy* create_int_proxy(); // <-- my proxy
};
class Int : public ValObject
{
public:
Int (int v) : val(v) {}
IntProxy* create_int_proxy() { return new IntProxy(&val); }
private:
int val;
};
class String : public ValObject
{
public:
String(const string& s) : val(s) {}
IntProxy* create_int_proxy() { return 0; }
private:
string val;
};
The client could then use this proxy to set and get the values of an Int through an ValObject:
ValObject *val = ... // some object
IntProxy *ipr = val->create_int_proxy();
assert(ipr); // we know that val is an Int (somehow)
ipr->set_val(17);
But with this design, i still have too many classes to declare and implement in the various subclasses. Is this the correct way to go ? Are there any alternatives ?
Thank you.
Take a look at boost::any and boost::variant for existing solutions. The closest to what you propose is boost::any, and the code is simple enough to read and understand even if you want to build your own solution for learning purposes --if you need the code, don't reinvent the wheel, use boost::any.
One of the beauties of C++ is that these kinds of intrusive solutions often aren't necessary, yet unfortunately we still see similar ones being implemented today. This is probably due to the prevalence of Java, .NET, and QT which follows these kinds of models where we have a general object base class which is inherited by almost everything.
By intrusive, what's meant is that the types being used have to be modified to work with the aggregate system (inheriting from a base object in this case). One of the problems with intrusive solutions (though sometimes appropriate) is that they require coupling these types with the system used to aggregate them: the types become dependent on the system. For PODs it is impossible to use intrusive solutions directly as we cannot change the interface of an int, e.g.: a wrapper becomes necessary. This is also true of types outside your control like the standard C++ library or boost. The result is that you end up spending a lot of time and effort manually creating wrappers to all kinds of things when such wrappers could have been easily generated in C++. It can also be very pessimistic on your code if the intrusive solution is uniformly applied even in cases where unnecessary and incurs a runtime/memory overhead.
With C++, a plethora of non-intrusive solutions are available at your fingertips, but this is especially true when we know that we can combine static polymorphism using templates with dynamic polymorphism using virtual functions. Basically we can generate these base object-derived wrappers with virtual functions on the fly only for the cases in which this solution is needed without pessimizing the cases where this isn't necessary.
As already suggested, boost::any is a great model for what you want to achieve. If you can use it directly, you should use it. If you can't (ex: if you are providing an SDK and cannot depend on third parties to have matching versions of boost), then look at the solution as a working example.
The basic idea of boost::any is to do something similar to what you are doing, only these wrappers are generated at compile-time. If you want to store an int in boost::any, the class will generate an int wrapper class which inherits from a base object that provides the virtual interface required to make any work at runtime.
The main problem I'm facing is how to
set/get the values through a pointer
to the base class ValObject. At first,
i thought i could just create lots of
functions in the base class, like
set_int, get_int, set_string,
get_string, set_value_for_key,
get_value_for_key, etc, and make them
work only for the correct types. But
then, i would have lots of cases where
functions do nothing and just pollute
my interface.
As you already correctly deduced, this would generally be an inferior design. One tell-tale sign of inheritance being used improperly is when you have a lot of base functions which are not applicable to your subclasses.
Consider the design of I/O streams. We don't have ostreams with functions like output_int, output_float, output_foo, etc. as being directly methods in ostream. Instead, we can overload operator<< to output any data type we want in a non-intrusive fashion. A similar solution can be achieved for your base type. Do you want to associate widgets with custom types (ex: custom property editor)? We can allow that:
shared_ptr<Widget> create_widget(const shared_ptr<int>& val);
shared_ptr<Widget> create_widget(const shared_ptr<float>& val);
shared_ptr<Widget> create_widget(const shared_ptr<Foo>& val);
// etc.
Do you want to serialize these objects? We can use a solution like I/O streams. If you are adapting your own solution like boost::any, it can expect such auxiliary functions to already be there with the type being stored (the virtual functions in the generated wrapper class can call create_widget(T), e.g.
If you cannot be this general, then provide some means of identifying the types being stored (a type ID, e.g.) and handle the getting/setting of various types appropriately in the client code based on this type ID. This way the client can see what's being stored and deal set/get values on it accordingly.
Anyway, it's up to you, but do consider a non-intrusive approach to this as it will generally be less problematic and a whole lot more flexible.
Use dynamic_cast to cast up the hierarchy. You don't need to provide an explicit interface for this - any reasonable C++ programmer can do that. If they can't do that, you could try enumerating the different types and creating an integral constant for each, which you can then provide a virtual function to return, and you can then static_cast up.
Finally, you could consider passing a function object, in double-dispatch style. This has a definite encapsulation advantage.
struct functor {
void operator()(Int& integral) {
...
}
void operator()(Bool& boo) {
...
}
};
template<typename Functor> void PerformOperationByFunctor(Functor func) {
if (Int* ptr = dynamic_cast<Int*>(this)) {
func(*ptr);
}
// Repeat
}
More finally, you should avoid creating types where they've basically been already covered. For example, there's little point providing a 64bit integral type and a 32bit integral type and ... it's just not worth the hassle. Same with double and float.