3

I'm implementing a Event template with C++ as below

Template.h

template<typename EventArg>
class Event {
public:
    typedef void (*EventHandle)(const EventArg&);
    vector<EventHandle> EventHandles;


protected:
    virtual void Init() { throw EventNotInitialized();};
    Event() 
    {
        printf("Event() \n");
        Init();
    }
};

Event.h

struct E_EventArgs {
    string data;
};
class E_Event : public Event<E_EventArgs>
{
public:
    static E_Event * Get() {
        static auto ins = new E_Event();
        return ins;
    }
protected:
    void Init() override {
        printf("E_Event() Init() \n");
    }
    E_Event() {
        Init();
        printf("E_Event() \n");
    }
};

Then I call E_Event::Get() to access to E_Event. But Here is the log:

Event()

I using arm-oe-linux-gnueabi-g++ (gcc version 6.4.0 (GCC))

Why constructor of E_Event is not called?

Silver
  • 406
  • 2
  • 12
  • 3
    Why do you think the `E_Event` constructor is not called? (I believe you have jumped to an unwarranted conclusion.) Maybe the situation would be clearer if you replaced `throw EventNotInitialized();` with `printf("Event() Init() \n");`? – JaMiT Aug 24 '21 at 05:06
  • 1
    After you try that experiment, see [Calling virtual functions inside constructors](https://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors). – JaMiT Aug 24 '21 at 05:13
  • The constructor is being called. The question to you is this -- what version of `Init()` is being called in the constructor of `E_Event`? Surprised? – PaulMcKenzie Aug 24 '21 at 05:16
  • @JaMiT you were right. The throw happen before the constructor call. – Silver Aug 24 '21 at 07:05
  • @Silver With this new insight (that the constructor of `E_Event` *is* called), can you write a more precise question that better represents the situation? *(Obligatory disclaimer, even though it seems unlikely to me: If editing this question would invalidate the current answer, the new version should be a new question.)* – JaMiT Aug 26 '21 at 04:40
  • @JaMiT I'm sorry, that I may misunderstand you. But I the situation is that the constructor of `E_Event` is never reach because I mistakenly throw an exception in its base class' constructor. There will be no question if constructor of `E_Event` is called. – Silver Aug 26 '21 at 07:58
  • @Silver: *"the situation is that the constructor of `E_Event` is never reach"* -- no, but you would be correct if you said that **the body** of the constructor of `E_Event` is never reached. What do you think is calling the constructor of `Event`? It doesn't happen out of thin air. The constructor of `Event` is being called by the constructor of `E_Event`, which you can see when you don't throw an exception. You could [make the call explicit](https://stackoverflow.com/questions/2311625/what-is-the-importance-of-invoking-base-class-constructor-explicitly) if you want it even more clear. – JaMiT Aug 26 '21 at 22:17
  • Hmm... the answer to your question might lie in [Order of calling constructors/destructors in inheritance](https://stackoverflow.com/questions/7539282) or in a question marked as a duplicate of that, [why constructor of base class invokes first?](https://stackoverflow.com/questions/45128900) *Note that in neither case is a template required. You could have removed this unnecessary complication from your question to help you better focus your question.* – JaMiT Aug 26 '21 at 22:20

1 Answers1

3

What you observe is not much of a consequence of calling a virtual function from a constructor.

In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn’t yet happened. Objects are constructed from the base up, “base before derived”.

Which means when you call Init() from E_Event's constructor, the most "recent" overridden version of Init() is of the base class Event.

However in your case the Init() call from E_Event's constructor doesn't happen.

When you construct a derived class, an instance of base class is also constructed. Consider this simple example.

#include <iostream>
class Base
{
public:
    Base()
    {
        std::cout<<"Base constructor"<<std::endl;
    }
};
class Derived: public Base
{
public:
    Derived()
    {
        std::cout<<"Derived constructor";
    }
};
int main()
{
  Derived();
}

The output will be

Base constructor
Derived constructor

As you can see, the constructor of Base is also called. So from E_Event's constructor the Event() is also called, which already throws exception, that's why whatever will be in E_Event won't be called.

Karen Baghdasaryan
  • 2,407
  • 6
  • 24