My reason for asking the question:
I am using a large framework not of my own design. I need to use several "user information" classes which are unrelated as far as the code is concerned. They do not derive from any common base class, and I do not have access to the source code to recompile.
These information classes work like this: there are classes A, B, C, etc. These classes each have an information class, Ainfo, Binfo, etc. associated with them. Because the user (i.e. me) needs to attach different informations to a given object of a given class (meaning I might have two different classes deriving from Ainfo that I want to attach to an object of A), and there is only one information slot, I want to make an information object that can old other various information objects. That way, I can just add my information into this fake information-object-which-is-a-container-for-other-information-objects.
The problem arises in that I would like to do this for Ainfo, Binfo, Cinfo, Dinfo etc. So I would like to write a mixin or something that just adds the container functionality to any of the plain old info classes.
The problem is that the information classes Ainfo, Binfo, etc. require different constructor arguments.
So the question:
Is it possible to pass a vector of types into the constructor of the mixin? That way I could have a variable list of appropriate constructor parameters passed in? Can you assign a type to a variable outside of a template argument? Can you cast with this variable?
or
Is it possible to inherit from a specific object? Could I for example create a new Ainfo object using the correct constructor, then do the mixin on that specific object. This would be like the usage of the decorator pattern, except I have no common interface. (the object being decorated is the interface)
or
am I just going to have to bite the bullet and write 15,000 (exaggeration :) ) classes which are exactly the same, but inherit from a different base class and contain a different type of object?
Summary:
I need to add a container feature to several different classes while maintaining the interface of each class and utilizing their argument-taking constructors. I would like to not duplicate code.
Thanks in advance. Sorry for totally butchering terminology.
It sounds to me like what you want is a Boost.Variant. It's like a C++-style union. It is strongly typed (so that you always know what you actually stored in it), and it has a powerful visitation mechanism that makes it easy to map many different types to a single operation.
For example, you can do this:
typedef boost::variant<Ainfo, Binfo, Cinfo> CommonInfo;
//In a function.
CommonInfo someInfo = Ainfo();
You can then write visitor functors that can be used to call members of the info objects.
class DoThingInfoVisitor : boost::static_visitor<>
{
void operator()(Ainfo &info) {info.DoThing()}
void operator()(Binfo &info) {info.DoThing2()}
void operator()(Cinfo &info) {info.StepA(); info.StepB();}
};
Armed with this object, if you want to do whatever this DoThing means for any CommonInfo type:
CommonInfo someInfo = Ainfo();
boost::apply_visitor( times_two_visitor(), someInfo );
This will call the Ainfo version, since that's what happens to be stored in someInfo. If it had stored Binfo, then you could use that. You can build a suite of these visitors; they can return values, take parameters (though you'll need to store them in the functor), and various other tricks you can learn from the docs.
If it's not doable in templates, and you can't hack it with the preprocessor, then you're gonna have to do it by hand. C++ doesn't contain any type manipulation at run-time, typeid() and dynamic_cast is all you've got.
This may be a bit of an oversimplification, but if nothing else it should help to clarify your question. Using templates, you can easily generate classes that derive from your info classes. The following classes illustrate this concept.
class Ainfo {
std::string _a;
public:
void setContent(const std::string& A);
const char * print() const; // prints _a
};
class Binfo {
std::string _b;
public:
void setContent(const std::string& B);
const char * print() const; // prints _b
};
template<class Tinfo>
class Info : public Tinfo {
};
You could then use this template as follows.
Info<Ainfo> my_info;
my_info.setContent("test");
std::cout << my_info.print();
UPDATE: If you also want to override the template's constructor, try using a member template.
template<class Tinfo>
class Info : public Tinfo {
public:
template<typename arg>
Info(arg rhs) : Tinfo(rhs) { }
};
Using this, you can compile and run the following.
Info<Ainfo> my_info("Testing...");
std::cout << my_info.print();
I could be wrong, but I have a feeling that we're getting pretty close now...
Related
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'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.
I am considering a factory function to create different classes in the same hierarchy. I understand that normally a factory is normally implemented as follows:
Person* Person::Create(string type, ...)
{
// Student, Secretary and Professor are all derived classes of Person
if ( type == "student" ) return new Student(...);
if ( type == "secretary" ) return new Secretary(...);
if ( type == "professor" ) return new Professor(...);
return NULL;
}
I am trying to think of a way so that the process can be automated so that the various conditions do not need to be hard-coded.
So far the only way I can think of is using a map and the prototype pattern:
The map will hold the type string in the first element and a class instance (prototype) in the second:
std::map<string, Person> PersonClassMap;
// This may be do-able from a configuration file, I am not sure
PersonClassMap.insert(make_pair("student", Student(...)));
PersonClassMap.insert(make_pair("secondary", Secretary(...)));
PersonClassMap.insert(make_pair("professor", Professor(...)));
The function may look something like this:
Person* Person::Create(string type)
{
map<string, Person>::iterator it = PersonClassMap.find(type) ;
if( it != PersonClassMap.end() )
{
return new Person(it->second); // Use copy constructor to create a new class instance from the prototype.
}
}
Unfortunately, the prototype method only works if you only want the class created by the factory to be identical every time, since it does not support arguments.
Does anybody know if it is possible to do it in a nice way, or am I stuck with the factory function?
I usually build a factory method (or a factory object) when the clients will be providing some information about the object to be created, but they don't know what concrete class the result will be. The determination about how to express the interface to the factory depends completely on what information the clients have. It could be that they provide a string (program text to be parsed, for example), or a set of parameter values (number of dimensions and sizes if we're creating geometric objects in n-space). The factory method then examines the information and decides what kind of object to create or which more specific factory to call.
So the decision about what to build shouldn't be made by the caller; if she knows, then there's no reason for a factory. If the list of things to be built is open-ended, you might even have a registration protocol that allows specific implementations to provide both their construction method and a discriminator function that would allow the factory method to decide which method to call.
It very much depends on what information is necessary and sufficient to decide which kind of object to build.
You can register a factory method (instead of the prebuilt element to copy). This will allow you to call the abstract factory with parameters that are passed to the concrete factory. The limitation here is that the set of parameters of all concrete factories must be the same.
typedef std::string discriminator;
typedef Base* (*creator)( type1, type2, type3 ); // concrete factory, in this case a free function
typedef std::map< discriminator, creator > concrete_map;
class Factory // abstract
{
public:
void register_factory( discriminator d, creator c ) {
factories_[ d ] = c;
}
Base* create( discriminator d, type1 a1, type2 a2, type3 a3 )
{
return (*(factories_[ d ]))( a1, a2, a3 );
}
private:
concrete_map factories_;
};
I have used free function creators to reduce the sample code, but you can define a concrete_factory type and use it instead of the 'creator' element above. Again, as you can see, you are limited to a fixed set of arguments in the factory 'create' method.
Each concrete factory can pass the arguments to the constructor of the given type:
Base* createDerived1( type1 a1, type2 a2, type3 a3 )
{
return new Derived1( a1, a2, a3 );
}
This is more flexible than your approach as you can create instances that hold references to external objects (those can only be initialized during construction) or constant members, or objects that cannot be reset to a different state after construction in a more general wording.
I would add a pure abstract clone method to class Person (which definitely looks like it should be an abstract class, existing mainly for the sake of being subclassed -- if you need a concrete "none of the above" kind of Person it's best done via a separate concrete subclass OtherKindOfPerson, rather than as the base class itself):
virtual Person* clone() const = 0;
and override it in every concrete subclass, e.g. in Student, with a new that invokes the specific concrete subclass's copy ctor:
Person* clone() const { return new Student(*this); }
You also need to change the registry map to:
std::map<string, Person*> PersonClassMap;
[[You could use some smarter pointer than a plain old Person *, but as the map and all of its entries probably needs to survive as long as the process does, this is definitely not a big deal -- the main added value you might get from smarter pointers being smarter behavior upon destruction of the "pointer"!-)]]
Now, your factory function can simply end with:
return it->second->clone();
The changes are needed to avoid the "slicing" effect of using the base class's copy ctor on a subclass that has extra attributes, as well as preserve any virtual method's resolution.
Subclassing a concrete class to yield other concrete classes is a bad idea exactly because these effects can be tricky and a source of bugs (see Haahr's recommendation against it: he writes about Java, but the advice is also good for C++ and other languages [indeed I find his recommendation even more crucial in C++!].
I am not familar with c++ but in many langugaes there concepts of delegates or closures. Means that instead of mapping to instance, you map to the function(delegate, closure) that is responsible to create object.
You could make an enum of each type of person:
enum PersonType { student, secretary, professor };
Well if you want a faster way to do it then using an enum and a switch statement will be many time faster than processing sequential if/else if statements ...
If you look at your two implementations, logically they are identical.
The first implementation is the same as your second if the recursive loop was unrolled. So really there is no advantage of your second implementation.
Regardless what you do you will need to list some where your types mapped to your constructors.
One way of doing it that can be useful is to have this map in a seperate xml file
<person>
<type> student </type>
<constructor> Student </type>
</person>
....
You can then read this xml file in to memory and use reflection to get back your constructor. For the given type. Given that you are using C++ however this will not be that simple as C++ does not have reflection as standard. You will have to look for an extension to provide you with reflection in C++.
But regardless, all these alternatives can not escape what you did in your original implementioan, ie: list the mapping from type to constructor and search the map.
I have an interesting problem. Consider this class hierachy:
class Base
{
public:
virtual float GetMember( void ) const =0;
virtual void SetMember( float p ) =0;
};
class ConcreteFoo : public Base
{
public:
ConcreteFoo( "foo specific stuff here" );
virtual float GetMember( void ) const;
virtual void SetMember( float p );
// the problem
void foo_specific_method( "arbitrary parameters" );
};
Base* DynamicFactory::NewBase( std::string drawable_name );
// it would be used like this
Base* foo = dynamic_factory.NewBase("foo");
I've left out the DynamicFactory definition and how Builders are
registered with it. The Builder objects are associated with a name
and will allocate a concrete implementation of Base. The actual
implementation is a bit more complex with shared_ptr to handle memory
reclaimation, but they are not important to my problem.
ConcreteFoo has class specific method. But since the concrete instances
are create in the dynamic factory the concrete classes are not known or
accessible, they may only be declared in a source file. How can I
expose foo_specific_method to users of Base*?
I'm adding the solutions I've come up with as answers. I've named
them so you can easily reference them in your answers.
I'm not just looking for opinions on my original solutions, new ones
would be appreciated.
The cast would be faster than most other solutions, however:
in Base Class add:
void passthru( const string &concreteClassName, const string &functionname, vector<string*> args )
{
if( concreteClassName == className )
runPassThru( functionname, args );
}
private:
string className;
map<string, int> funcmap;
virtual void runPassThru( const string &functionname, vector<string*> args ) {}
in each derived class:
void runPassThru( const string &functionname, vector<string*> args )
{
switch( funcmap.get( functionname ))
{
case 1:
//verify args
// call function
break;
// etc..
}
}
// call in constructor
void registerFunctions()
{
funcmap.put( "functionName", id );
//etc.
}
The CrazyMetaType solution.
This solution is not well thought out. I was hoping someone might
have had experience with something similar. I saw this applied to the
problem of an unknown number of a known type. It was pretty slick. I
was thinking to apply it to an unkown number of unknown type***S***
The basic idea is the CrazyMetaType collects the parameters is type
safe way, then executing the concrete specific method.
class Base
{
...
virtual CrazyMetaType concrete_specific( int kind ) =0;
};
// used like this
foo->concrete_specific(foo_method_id) << "foo specific" << foo_specific;
My one worry with this solution is that CrazyMetaType is going to be
insanely complex to get this to work. I'm up to the task, but I
cannot count on future users to be up to be c++ experts just to add
one concrete specific method.
Add special functions to Base.
The simplest and most unacceptable solution is to add
foo_specific_method to Base. Then classes that don't
use it can just define it to be empty. This doesn't work because
users are allowed to registers their own Builders with the
dynamic_factory. The new classes may also have concrete class
specific methods.
In the spirit of this solution, is one slightly better. Add generic
functions to Base.
class Base
{
...
/// \return true if 'kind' supported
virtual bool concrete_specific( int kind, "foo specific parameters" );
};
The problem here is there maybe quite a few overloads of
concrete_specific for different parameter sets.
Just cast it.
When a foo specific method is needed, generally you know that the
Base* is actually a ConcreteFoo. So just ensure the definition of class
ConcreteFoo is accessible and:
ConcreteFoo* foo2 = dynamic_cast<ConcreteFoo*>(foo);
One of the reasons I don't like this solution is dynamic_casts are slow and
require RTTI.
The next step from this is to avoid dynamic_cast.
ConcreteFoo* foo_cast( Base* d )
{
if( d->id() == the_foo_id )
{
return static_cast<ConcreteFoo*>(d);
}
throw std::runtime_error("you're screwed");
}
This requires one more method in the Base class which is completely
acceptable, but it requires the id's be managed. That gets difficult
when users can register their own Builders with the dynamic factory.
I'm not too fond of any of the casting solutions as it requires the
user classes to be defined where the specialized methods are used.
But maybe I'm just being a scope nazi.
The cstdarg solution.
Bjarn Stroustrup said:
A well defined program needs at most few functions for which the
argument types are not completely specified. Overloaded functions and
functions using default arguments can be used to take care of type
checking in most cases when one would otherwise consider leaving
argument types unspecified. Only when both the number of arguments and
the type of arguments vary is the ellipsis necessary
class Base
{
...
/// \return true if 'kind' supported
virtual bool concrete_specific( int kind, ... ) =0;
};
The disadvantages here are:
almost no one knows how to use cstdarg correctly
it doesn't feel very c++-y
it's not typesafe.
Could you create other non-concrete subclasses of Base and then use multiple factory methods in DynamicFactory?
Your goal seems to be to subvert the point of subclassing. I'm really curious to know what you're doing that requires this approach.
If the concrete object has a class-specific method then it implies that you'd only be calling that method specifically when you're dealing with an instance of that class and not when you're dealing with the generic base class. Is this coming about b/c you're running a switch statement which is checking for object type?
I'd approach this from a different angle, using the "unacceptable" first solution but with no parameters, with the concrete objects having member variables that would store its state. Though i guess this would force you have a member associative array as part of the base class to avoid casting to set the state in the first place.
You might also want to try out the Decorator pattern.
You could do something akin to the CrazyMetaType or the cstdarg argument but simple and C++-ish. (Maybe this could be SaneMetaType.) Just define a base class for arguments to concrete_specific, and make people derive specific argument types from that. Something like
class ConcreteSpecificArgumentBase;
class Base
{
...
virtual void concrete_specific( ConcreteSpecificArgumentBase &argument ) =0;
};
Of course, you're going to need RTTI to sort things out inside each version of concrete_specific. But if ConcreteSpecificArgumentBase is well-designed, at least it will make calling concrete_specific fairly straightforward.
The weird part is that the users of your DynamicFactory receive a Base type, but needs to do specific stuff when it is a ConcreteFoo.
Maybe a factory should not be used.
Try to look at other dependency injection mechanisms like creating the ConcreteFoo yourself, pass a ConcreteFoo type pointer to those who need it, and a Base type pointer to the others.
The context seems to assume that the user will be working with your ConcreteType and know it is doing so.
In that case, it seems that you could have another method in your factory that returns ConcreteType*, if clients know they're dealing with concrete type and need to work at that level of abstraction.