[C++] Inheritance not working from constructor?

Started by
10 comments, last by fyhuang 18 years, 9 months ago
Hey all, I'm having this small problem with my code - I have a base Singleton class (not a complete code listing):

class Singleton
{
public:
    void create();
    virtual int init() { return 0; }
    virtual int shutdown() { return 0; }

protected:
    Singleton()
    {
        init();
    }

    virtual ~Singleton()
    {
        shutdown();
    }
};

The purpose of this code is, when the Singleton is created, the init() function is called to perform initialization, and when it is destroyed, the shutdown() function is called to perform shutting-down. Classes that inherit from Singleton can override init() and shutdown(). My problem is - I have a derived class that overrides both init() and shutdown(), but when the Singleton is created, the base Singleton's init() function is called instead of the overridden init() function (obviously I want the overridden one to be called). Not implementing init() and shutdown() in Singleton of course causes the compiler to tell me that, I can't use those functions in the constructor/destructor because they're not defined. Since there's some error-checking code wrapping init() and shutdown() (not shown here), I don't want to copy & paste the constructor code to each derived class. Can anyone help me get this working? Thanks in advance!
- fyhuang [ site ]
Advertisement
Won't work. C++ (unlike C#) does not apply the "virtual" to functions called in the constructor/destructor for technical reasons.
Hmm. Would it work if I did something like this:

    // ...    void create()    {        if ( !ms_Singleton )        {            ms_Singleton = new T(); // Singleton< T > of course            init();        }    }


I figure that that might work for construction, but I still dunno about destruction...

Cheers!
- fyhuang [ site ]
Why do you need to do this? What's wrong with just putting the init and shutdown code in the derived class's constructor and destructor? That's what they're for...

Game Programming Blog: www.mattnewport.com/blog

The only good reason I can think of is that it allows me to handle errors more effectively. Otherwise, yes I suppose I should be just doing it in the constructor [smile].

Thanks and cheers!
- fyhuang [ site ]
That will probably work with some small changes:
    class Singleton    {    public:        static void create();        ...    };    void Singleton::create()    {        if ( !ms_Singleton )        {            ms_Singleton = new T(); // Singleton< T > of course            ms_Singleton->init();        }    } 
create() needs to be static so that you can call it without already having an instance of the class. There is probably no need make shutdown() virtual because with a virtual destructor, all the destructors are called.

John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Quote:Original post by fyhuang
Hey all,

I'm having this small problem with my code - I have a base Singleton class (not a complete code listing):

*** Source Snippet Removed ***

The purpose of this code is, when the Singleton is created, the init() function is called to perform initialization, and when it is destroyed, the shutdown() function is called to perform shutting-down. Classes that inherit from Singleton can override init() and shutdown().

My problem is - I have a derived class that overrides both init() and shutdown(), but when the Singleton is created, the base Singleton's init() function is called instead of the overridden init() function (obviously I want the overridden one to be called).

Not implementing init() and shutdown() in Singleton of course causes the compiler to tell me that, I can't use those functions in the constructor/destructor because they're not defined. Since there's some error-checking code wrapping init() and shutdown() (not shown here), I don't want to copy & paste the constructor code to each derived class.

Can anyone help me get this working? Thanks in advance!



Because in ctor the vtable slots not being completely setup yet,and in dtor,the vtable is restored back...
So,calling of init or shutdown is the CSingleton::init and CSingleton::shutdown,not any inheritance version...
God create the world,we create another one.-Reference
The reason for why this happens is described in detail here along with several possible workarounds (some of which have already been posted).

Quote:Original post by Andrew Russell
The reason for why this happens is described in detail here along with several possible workarounds (some of which have already been posted).

Thanks for that. I picked up a useful peice of know-how from that article I wasn't aware of.
In C++, an object of a derived class is progressively constructed.

Suppose you have class Base and derive from it, class Derived.

C++ first calls Base's constructor. If this contains virtual functions, they are not yet overridden, because at this point, the object is still a "Base" object (in fact, it's not really even that yet, it's partially complete).

Once the "Base" constructor is called, then the Derived constructor is called. At this point, the object has become (a partially constructed) a Derived. Therefore overridden virtual functions called *now*, will call Derived's ones.

If Derived's constructor throws an exception, Base's destructor will be called, but Derived's won't be (as it isn't yet *fully* constructed).

It all makes perfect sense - you *cannot* call a class's methods before its base class has been constructed - as they might in turn call methods of the base class which relied on private members of the base class which weren't assigned their right values yet, which would break (obviously).

(Note that this is different from Java, where you *can* do this, although it still doesn't make very much sense, and some people view it as a bug)

---

You might do better making Singleton a template class rather than a base class for your objects stored in it.

Mark

This topic is closed to new replies.

Advertisement