static Create function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Base{
    private:
        Base(int arg){
            GlobalVariable.BaseVector.append(this);}
    public:
        static Base& Create(int arg){
            return *(new Base(arg));}};

class Derived:public Base{
    public:
        float var;};

//...

Derived& d=Derived::Create(8);

Is there a way to do this so that Derived has its own Create function that creates a Derived variable on the heap and returns a reference to it?
Last edited on
Maybe if the "Create()" member function was a template. But it still wouldn't be able to set the variables that are unique to the 'Derived' class.
It doesn't need to set Derived-specific members. That's handled elsewhere. How would I make that a template function? Just

1
2
3
template<class T>
static T& Create(int arg){
    return *(new T(arg));}

?

But then I would have to use it like this: Derived& d=Derived::Create<Derived>(8) which I'd rather not do. I guess that can be plan B.
Last edited on
At a first glance that looks good. Give it a shot.
According to codepad.org (I'm not on my normal computer atm) I have to use it like this: Derived& d=Derived::Create<Derived>(8);
What about class factories?

Base::Create would handle an internal class factory collection of duh!, class factory objects. :D

1
2
3
4
5
class IClassFactory
{
public:
    Base& Create(int arg) = 0;
};


Then each derived class would have to provide its own class factory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Derived : public Base
{
    class _Factory : public IClassFactory
    {
    public:
        Base& Create(int arg)
        {
            return *(new Derived(int));
        }
    };
    static _Factory _myFactory;

    ....
public:
    static IClassFactory* GetFactory() { return &_myFactory; }
}


Now, there is still one more thing you need to define: How to identify the class factory the caller of Base::Create wants to be used. COM uses GUID's (and a more complex class factory mechanism). You could use typeid() and RTTI and use the returned typeid to index factories in a std::map collection, which also forces us to modify the original signature of Create():

1
2
3
4
5
6
class Base
{
    ....
    static Base& Create(int typeID, int arg);
    static std::map<int, IClassFactory*> _factories;
};


At this point you need to decide how to fill in the _factories collection. I think I would use a C array and I would construct it statically.

1
2
3
4
5
6
7
8
9
10
class Base
{
    ....
    static std::pair<int, IClassFactory*> __initFactories[];
    static std::map<int, IClassFactory*> _factories;
};

std::pair<int, IClassFactory*> Base::__initFactories[] = { std::pair(typeid(Derived), Derived::GetFactory()), std::pair(typeid(Derived2), Derived2::GetFactory()), ... };

std::map<int, IClassFactory*> Base::_factories(__initFactories, __initFactories + _countof(__initFactories));


And I think that does it. Now you can do:

Derived d = dynamic_cast<Derived&>Base::Create(typeid(Derived), someArg);

None of the above is tested, but hopefully you get the idea.

Personally though, I think this is a hard way of doing it (now that I have finished pouring the idea out). Since I am bound to identify the type with RTTI and typeid, what is my gain when compared to the templated way?
I might be missing the point - but I see no added value from any of the above methods of creating a derived classe.
they all create a derived class and assign it to a derived class pointer (possibly using a cast) - which
to me seem a bit moot when a simple

derived_class pointer = new derived_class( args) achieves exactly the same thing.



@webJose - That's looks extremely complicated for what seems like a simple problem, and a problem that has more to do with syntax sugar than anything else =\

@guestgulkan - I like using references better, and I'd rather not have something like:

Derived& d=*(new Derived);

But... I guess that's the only somewhat nice-looking, simple-to-implement solution.
Last edited on
Here's a little trick I stole from hamsterman:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct ClassA
{
    ClassA()    {}
    ClassA(int) {}
};

struct ClassB
{
    ClassB()     {}
    ClassB(char) {}
};

#define NEW(T) ( *(new T) )

int main()
{
    ClassA & a1 = NEW( ClassA    );
    ClassA & a2 = NEW( ClassA(7) );

    ClassB & b1 = NEW( ClassB      );
    ClassB & b2 = NEW( ClassB('c') );

    return 0;
}

Last edited on
I actually really like that trick... Thanks! :D
Thank hamsterman.
So, by using a #define statement instead of doing it in the actual code, it becomes a trick? I need to do this more often XD
I just want to say that hamsterman does some of the strangest things with Macro's.
L B wrote:
So, by using a #define statement instead of doing it in the
actual code, it becomes a trick? I need to do this more often XD

Haha. Actually, it was a little more than that -> http://cplusplus.com/forum/general/43842/#msg238239
Last edited on
Topic archived. No new replies allowed.