simulate virtual constructor in c++
In my application I have to derive some classes from a base one, the problem is that I want to enforce the derived classed to have 3 particular constructor implementation. As c++ don't have virtual pure constructor, it seemed quite desperate (I had to check manually each class implementation to ensure that the particular ctors are implemented,开发者_如何学编程 not quite fun to do).
Yesterday I found a crazy way to simulate the comportment of a virtual ctor:
template <class T>
class AbstractEnforcer{
protected:
AbstractEnforcer(){}
private:
static void Enforcer(){
delete new T();
delete new T(*(new unsigned int));
delete new T(*(new unsigned int, *(new QString));
}
}
class AbstractClass : private AbstractEnforcer<AbstractClass>{
}
the only inconvenience with this approach is that I have to to declare all derived class with the syntax:
class X : private AbstractEnforcer<X>
And even if it's not a problem; because the Enforcer() methode never get called (and even so it does nothing [hope so!!!])
My question is: "is there any mean (not with macros) to force the derived class to use this mechanism without parametrazing the AbstractClass (because this will work in only one level of derivation"
template <class T>
class AbstractClass : private AbstractEnforcer<T>{
}
Your solution does not solve the problem since templated code that isnt used is not instantiated, and thus unless you manually invoke this function - it will not verify the existence of the wanted constructors.
What you can do is have this method called from the constructor of your enforcer:
template <class T>
class AbstractEnforcer{
protected:
AbstractEnforcer(){ Enforcer(); }
private:
static void Enforcer(){
delete new T();
delete new T(*(new unsigned int));
delete new T(*(new unsigned int, *(new QString)));
}
// disable:
AbstractEnforcer (const AbstractEnforcer &enf);
};
class AbstractClass : private AbstractEnforcer<AbstractClass>{
};
int main () {
AbstractClass c;
}
Then, the compiler complains - mission accomplished.
Note that I've disabled the copy constructor so that there will be no way to bypass that check (by calling a different constructor).
Edit - Non leaking Enforcer(): [As there's absolutly no need to use dynamic allocations there..]
static void Enforcer(){
T t1();
T t2(int(3));
T t3(int(4), QString());
}
See this page in the C++ FAQ.
What I would do is something like this:
class AbstractClass { public: virtual AbstractClass* create() const = 0; virtual AbstractClass* create(unsigned int) const = 0; virtual AbstractClass* create(unsigned int, QString) const = 0; };
Then each of the derived classes would be forced to override these functions, which should create new objects with different constructors.
From this comment to one of the answers I think that you do not really want to achieve what you are asking here, but rather a different thing. The comment I refer to is:
Part 1:
I knew that we can't have a virtual constructor and I don't want to have one, my purpose is to a compiler static code checking that will alert me if I forgot to implement a specific constructor prototype.
Part 2:
My project is a plugin like dynamic loading system and I have in some way enforce the ctors prototypes implementation of the third party code.
What you are asking in the question is 1, and you can enforce it in different ways, just read some of the answers, or take a look at metaprogramming examples and the boost::type_traits library.
Now, if what you really want is part 2: provide a dynamic loading plugin mechanism then you do not need to enforce the constructors, but a common interface both for the plugin objects and the creation of the plugin objects. There is no way of instantiating an instance of an object of unknown (at compile time) object, and that means that you will not be able to call the constructors from your code. I would suggest
// Interface:
class plugin {
public:
virtual void operation() = 0;
};
class plugin_factory {
public:
virtual plugin* create() = 0;
virtual plugin* create( unsigned int ) = 0;
virtual plugin* create( unsigned int, QString const & ) = 0;
};
Users will need to provide the implementation of a plugin and the factory that creates them. They will probably need to implement a point of entry for their library so that you can get access to the factory (or so they can register their factory within your system, or else I would suggest using a library for these purposes (boost::extension seems like a place to look at)
I'd probably just have a template for generating a test:
template <typename T>
void enforceConstructors() {
T t1;
T t2(0);
QString q;
T t3(0, q);
}
Then somewhere in your tests, do:
enforceConstructors<X>();
enforceConstructors<Y>();
enforceConstructors<Z>();
Those might be all together, or in separate places for each of the classes X, Y, Z. Depends how you want to organise your tests.
If the values I used aren't suitable, either put in some values which are, or else compile that test but don't run it. If you don't have unit tests either get some, or else add the following to the class (instead of inheriting from the base class):
#ifndef NDEBUG
static void test() { enforceConstructors<X>(); }
#endif
You don't usually need to make constructors part of an interface defined by an abstract base class. The reason is that such interfaces are for dynamic polymorphism - you pass an object to some function, and it calls functions on it. You can't "pass" a class to a function and have it instantiate the class other than with templates. Templates mostly enforce their interfaces at compile time anyway - if you instantiate the template and it uses the constructor, then the constructor has to be there.
If you forget to implement the constructor but use it in your code, you will get a compilation error. For example:
Base * p = new Derived( 42 );
will be a compile-time error if the Derived(int) constructor is not provided - the Base constructor will not be used.
I finally adopted this solution, but not quit convienced:
#ifdef NDEBUG
#ifndef ENFORCE_CTORS
#define ENFORCE_CTORS(enforcingTemplate, enforcedClass) \
friend void enforcingCtors(){static enforcingTemplate<enforcedClass> _enforcer;}
#endif
template<class T>
class AbstractEnforcer : T{
public:
explicit AbstractEnforcer(){
T enforcedCtor0( );
T enforcedCtor1( *(new unsigned int) );
T enforcedCtor2( *(new unsigned int), *(new QString) );
T enforcedCtor3( *(new unsigned int), *(new float ) );
}
};
#endif
and in each class that I wan't to enforce I just add like this:
class X{
ENFORCE_CTORS(AbstractEnforcer, X);
/*
.....
*/
}
I didn't find any other way to inject this code dynamically in a class. And I may been unclear about the final purpose of the operation (sorry for my terrible English).
精彩评论