Why is the Base class Constructor getting called twice

Discussion in 'C++' started by Robert, Dec 10, 2003.

  1. Robert

    Robert Guest

    Hello all...

    In my code below, the Notify Constructor and Destructor is getting
    called twice and it appears that a new Notify object is created on the
    2nd call. The 2nd call is caused by this line below: pNotify = new
    EMAILnotify; that lives in the Notification Constructor.

    One theory is that the Notify base class is not completely constructed
    prior to using it in the Notification Constructor code: pNotify = new
    EMAILnotify;

    All the code below can be pasted into a *.cpp module and will compile
    and run with a VC++6.0 compiler.

    Thanks in advance for any clues as to why?

    **************************************************************
    #include <iostream>
    #include <string>

    using namespace std;

    class Notify
    {
    public:
    Notify(void){ cout << "Constructing Notify: " << this << endl; }
    virtual ~Notify(void){ cout << "Destructing Notify: " << this <<
    endl; }
    virtual void Send() = 0;
    };
    class Notification : public Notify
    {
    public:
    Notification(void){}
    Notification(string sNotifyType);
    virtual ~Notification(void);
    void Send(){ pNotify->Send(); }
    private:
    Notify* pNotify;

    };
    class EMAILnotify : public Notify
    {
    public:
    EMAILnotify(void){}
    virtual ~EMAILnotify(void){};
    virtual void Send(){ cout << "Send() Email: " << this << endl; }
    };
    Notification::Notification(string sNotifyType)
    {
    if(sNotifyType == "EMAIL")
    pNotify = new EMAILnotify; // Causes 2nd Constructor call
    }
    Notification::~Notification(void)
    {
    if( NULL != pNotify )
    delete pNotify;
    }

    void main()
    {
    Notification* pNotification = new Notification("EMAIL");
    pNotification->Send();
    delete pNotification;
    }
     
    Robert, Dec 10, 2003
    #1
    1. Advertising

  2. On 10 Dec 2003 10:20:24 -0800, (Robert) wrote:

    >In my code below, the Notify Constructor and Destructor is getting
    >called twice and it appears that a new Notify object is created on the
    >2nd call. The 2nd call is caused by this line below: pNotify = new
    >EMAILnotify; that lives in the Notification Constructor.


    Class Notification derives from Notify. The calling sequence is:
    (1) create a Notification object, which executes the Notify constructor,
    and then (2) executes the Notification constructor body, which (3)
    executes pNotify = new EMAILnotify, which (4) creates an EMAILnotify
    object, where EMAILnotify is derived from Notify, so that this creation
    (5) executes the Notify constructor for the EMAILnotify object, and (6)
    proceeds to execute the EMAILnotify constructor body.


    >...
    >
    >**************************************************************
    >#include <iostream>
    >#include <string>
    >
    >using namespace std;
    >
    >class Notify


    This is a bad name for a class. A class doesn't "do" anything,
    unless it's a functor class. Which this isn't.


    >{
    >public:
    > Notify(void){ cout << "Constructing Notify: " << this << endl; }


    Style.
    'void' as an argument list is a C'ism which you'd better forget.



    > virtual ~Notify(void){ cout << "Destructing Notify: " << this <<
    >endl; }
    > virtual void Send() = 0;
    >};


    Style.
    At least one empty line between class declarations is a good idea.



    >class Notification : public Notify
    >{
    >public:
    > Notification(void){}
    > Notification(string sNotifyType);
    > virtual ~Notification(void);
    > void Send(){ pNotify->Send(); }
    >private:
    > Notify* pNotify;
    >
    >};


    Style.
    The definitions of the Notification member functions should appear
    here, before anything more. One "place" per class in the code.

    Design.
    Having a pNotify member doesn't seem to serve any useful purpose.
    Most probably you have tried to implement too much in one class.



    >class EMAILnotify : public Notify
    >{
    >public:
    > EMAILnotify(void){}
    > virtual ~EMAILnotify(void){};
    > virtual void Send(){ cout << "Send() Email: " << this << endl; }
    >};
    >Notification::Notification(string sNotifyType)
    >{
    > if(sNotifyType == "EMAIL")


    Design.
    Don't identify types by strings (in general). Use symbolic constants
    if you absolutely have to. But even more to the point: don't identify
    types by data unless you really Really REALLY have to.


    > pNotify = new EMAILnotify; // Causes 2nd Constructor call
    >}
    >Notification::~Notification(void)
    >{
    > if( NULL != pNotify )


    Coding.
    No need to check for NULL.


    > delete pNotify;
    >}
    >
    >void main()


    C++ standard.
    'void main' is not allowed. This is not a valid standard C++ program.


    >{
    > Notification* pNotification = new Notification("EMAIL");
    > pNotification->Send();
    > delete pNotification;


    Style.
    The above is not exception safe in any sense. Use a std::auto_ptr.


    >}
     
    Alf P. Steinbach, Dec 10, 2003
    #2
    1. Advertising

  3. Robert wrote:
    ....
    >
    > Thanks in advance for any clues as to why?


    because you inherit notify in two different classes and instantiate both
    classes.

    >
    > **************************************************************
    > #include <iostream>
    > #include <string>
    >
    > using namespace std;
    >
    > class Notify
    > {
    > public:
    > Notify(void){ cout << "Constructing Notify: " << this << endl; }
    > virtual ~Notify(void){ cout << "Destructing Notify: " << this <<
    > endl; }
    > virtual void Send() = 0;
    > };
    > class Notification : public Notify


    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inherit 1

    > {
    > public:
    > Notification(void){}
    > Notification(string sNotifyType);
    > virtual ~Notification(void);
    > void Send(){ pNotify->Send(); }
    > private:
    > Notify* pNotify;
    >
    > };
    > class EMAILnotify : public Notify



    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inherit 2


    > {
    > public:
    > EMAILnotify(void){}

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ : Notify() implicitly constructed here


    > virtual ~EMAILnotify(void){};
    > virtual void Send(){ cout << "Send() Email: " << this << endl; }
    > };
    > Notification::Notification(string sNotifyType)

    : Notify() // implicit construct of Notify


    > {
    > if(sNotifyType == "EMAIL")
    > pNotify = new EMAILnotify; // Causes 2nd Constructor call

    // Making second Notify here

    > }
    > Notification::~Notification(void)
    > {
    > if( NULL != pNotify )
    > delete pNotify;
    > }
    >
    > void main()


    must use int - not void....

    int main()

    > {
    > Notification* pNotification = new Notification("EMAIL");
    > pNotification->Send();
    > delete pNotification;
    > }
     
    Gianni Mariani, Dec 10, 2003
    #3
  4. Robert wrote:
    >
    > Hello all...
    >
    > In my code below, the Notify Constructor and Destructor is getting
    > called twice and it appears that a new Notify object is created on the
    > 2nd call. The 2nd call is caused by this line below: pNotify = new
    > EMAILnotify; that lives in the Notification Constructor.
    >
    > One theory is that the Notify base class is not completely constructed
    > prior to using it in the Notification Constructor code: pNotify = new
    > EMAILnotify;


    The ctor is called twice because you create 2 Notify objects.

    Object 1:
    Notification* pNotification = new Notification("EMAIL");

    Object 2: inside the ctor of Notification
    pNotify = new EMAILnotify;

    It seems you have a design error. From what I can see, you don't
    want a Notification object to be a Notify object at the same time.
    A Notification object *contains* a Notify object, but that's it. A
    Notification is not a Notify on its own.

    class Notification
    {
    ....

    Notify* pNotify;
    };


    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, Dec 10, 2003
    #4
  5. Robert

    Robert Guest

    (Alf P. Steinbach) wrote in message news:<>...
    > On 10 Dec 2003 10:20:24 -0800, (Robert) wrote:
    >
    > >In my code below, the Notify Constructor and Destructor is getting
    > >called twice and it appears that a new Notify object is created on the
    > >2nd call. The 2nd call is caused by this line below: pNotify = new
    > >EMAILnotify; that lives in the Notification Constructor.

    >
    > Class Notification derives from Notify. The calling sequence is:
    > (1) create a Notification object, which executes the Notify constructor,
    > and then (2) executes the Notification constructor body, which (3)
    > executes pNotify = new EMAILnotify, which (4) creates an EMAILnotify
    > object, where EMAILnotify is derived from Notify, so that this creation
    > (5) executes the Notify constructor for the EMAILnotify object, and (6)
    > proceeds to execute the EMAILnotify constructor body.
    >


    Thanks for all the information and tips...

    > >...
    > >
    > >**************************************************************
    > >#include <iostream>
    > >#include <string>
    > >
    > >using namespace std;
    > >
    > >class Notify

    >
    > This is a bad name for a class. A class doesn't "do" anything,
    > unless it's a functor class. Which this isn't.
    >


    Agreed!...

    > >{
    > >public:
    > > Notify(void){ cout << "Constructing Notify: " << this << endl; }

    >
    > Style.
    > 'void' as an argument list is a C'ism which you'd better forget.
    >


    Agreed!, that's what I get for cutting and pasting sample code.

    >
    > > virtual ~Notify(void){ cout << "Destructing Notify: " << this <<
    > >endl; }
    > > virtual void Send() = 0;
    > >};

    >
    > Style.
    > At least one empty line between class declarations is a good idea.
    >


    This was a post, need to keep it short.

    >
    > >class Notification : public Notify
    > >{
    > >public:
    > > Notification(void){}
    > > Notification(string sNotifyType);
    > > virtual ~Notification(void);
    > > void Send(){ pNotify->Send(); }
    > >private:
    > > Notify* pNotify;
    > >
    > >};

    >
    > Style.
    > The definitions of the Notification member functions should appear
    > here, before anything more. One "place" per class in the code.


    Again, this was a post, the real code is in separate modules.

    > Design.
    > Having a pNotify member doesn't seem to serve any useful purpose.
    > Most probably you have tried to implement too much in one class.
    >


    pNotify as a member is vital in supporting the strategy pattern.
    Please correct me if I'm wrong.

    >
    > >class EMAILnotify : public Notify
    > >{
    > >public:
    > > EMAILnotify(void){}
    > > virtual ~EMAILnotify(void){};
    > > virtual void Send(){ cout << "Send() Email: " << this << endl; }
    > >};
    > >Notification::Notification(string sNotifyType)
    > >{
    > > if(sNotifyType == "EMAIL")

    >
    > Design.
    > Don't identify types by strings (in general). Use symbolic constants
    > if you absolutely have to. But even more to the point: don't identify
    > types by data unless you really Really REALLY have to.
    >


    Agreed!, but then how would I identify a type at run time via
    polymorphism?

    > > pNotify = new EMAILnotify; // Causes 2nd Constructor call
    > >}
    > >Notification::~Notification(void)
    > >{
    > > if( NULL != pNotify )

    >
    > Coding.
    > No need to check for NULL.
    >


    Yep!

    > > delete pNotify;
    > >}
    > >
    > >void main()

    >
    > C++ standard.
    > 'void main' is not allowed. This is not a valid standard C++ program.
    >


    When I test sample code, no need to worry about Standards that would
    not cause bugs...

    > >{
    > > Notification* pNotification = new Notification("EMAIL");
    > > pNotification->Send();
    > > delete pNotification;

    >
    > Style.
    > The above is not exception safe in any sense. Use a std::auto_ptr.
    >


    This is sample code, in the real program it is wrapped in a
    try{}catch{}

    > >}



    Thanks again for your tips...

    --Robert
     
    Robert, Dec 11, 2003
    #5
  6. Robert wrote:
    >
    > > Design.
    > > Don't identify types by strings (in general). Use symbolic constants
    > > if you absolutely have to. But even more to the point: don't identify
    > > types by data unless you really Really REALLY have to.
    > >

    >
    > Agreed!, but then how would I identify a type at run time via
    > polymorphism?


    By not identifying them at all.
    In your case: Why pass a string identifying the type of notify
    when you can pass a Notify object at the same time.

    class Notification
    {
    public:
    Notification( Notify* pNotify ) : m_pNotify( pNotify ) {}
    ~Notification() { delete pNotify; }
    void Send() { m_pNotify->Send(); }
    ...

    private:
    Notify* m_pNotify;
    };

    class Notify
    {
    public:
    virtual ~Notify();
    ...
    virtual void Send() = 0;
    };

    class EMailNotify : public Notify
    {
    public:
    EMailNotify( std::string& To ) : m_To( To ) {}
    ...
    virtual void Send() { std::cout << "Sending EMail to " << m_To << std::endl;

    private:
    std::string m_To;
    };

    class SnailMailNotify : public Notify
    {
    public:
    SnailMailNotify( std::String& To ) : m_To( To ) {}
    ...
    virtual void Send() { std::cout << "Sending snail mail to " << m_To << std::endl;

    private:
    std::string m_To;
    };


    int main()
    {
    Notification* pEvent1 = new Notification( new EmailNotification( "" ) );
    Notification* pEvent2 = new Notification( new SnailMailNotify( "Robert" ) );

    pEvent1->Send();
    pEvent2->Send();

    >
    > When I test sample code, no need to worry about Standards that would
    > not cause bugs...
    >


    If you post in this group and use void main() you will always get a reply
    for that. Plain and simple: void main() is wrong. The fact that your
    compiler allows you to use it is irrelevant. It is still wrong.

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, Dec 11, 2003
    #6
  7. Robert

    jb Guest

    (Alf P. Steinbach) wrote in message news:<>...
    > On 10 Dec 2003 10:20:24 -0800, (Robert) wrote:
    >
    > >In my code below, the Notify Constructor and Destructor is getting
    > >called twice and it appears that a new Notify object is created on the
    > >2nd call. The 2nd call is caused by this line below: pNotify = new
    > >EMAILnotify; that lives in the Notification Constructor.

    >
    > Class Notification derives from Notify. The calling sequence is:
    > (1) create a Notification object, which executes the Notify constructor,
    > and then (2) executes the Notification constructor body, which (3)
    > executes pNotify = new EMAILnotify, which (4) creates an EMAILnotify
    > object, where EMAILnotify is derived from Notify, so that this creation
    > (5) executes the Notify constructor for the EMAILnotify object, and (6)
    > proceeds to execute the EMAILnotify constructor body.
    >
    >
    > >...
    > >
    > >**************************************************************
    > >#include <iostream>
    > >#include <string>
    > >
    > >using namespace std;
    > >
    > >class Notify

    >
    > This is a bad name for a class. A class doesn't "do" anything,
    > unless it's a functor class. Which this isn't.
    >
    >
    > >{
    > >public:
    > > Notify(void){ cout << "Constructing Notify: " << this << endl; }

    >
    > Style.
    > 'void' as an argument list is a C'ism which you'd better forget.
    >
    >
    >
    > > virtual ~Notify(void){ cout << "Destructing Notify: " << this <<
    > >endl; }
    > > virtual void Send() = 0;
    > >};

    >
    > Style.
    > At least one empty line between class declarations is a good idea.
    >
    >
    >
    > >class Notification : public Notify
    > >{
    > >public:
    > > Notification(void){}
    > > Notification(string sNotifyType);
    > > virtual ~Notification(void);
    > > void Send(){ pNotify->Send(); }
    > >private:
    > > Notify* pNotify;
    > >
    > >};

    >
    > Style.
    > The definitions of the Notification member functions should appear
    > here, before anything more. One "place" per class in the code.
    >
    > Design.
    > Having a pNotify member doesn't seem to serve any useful purpose.
    > Most probably you have tried to implement too much in one class.
    >
    >
    >
    > >class EMAILnotify : public Notify
    > >{
    > >public:
    > > EMAILnotify(void){}
    > > virtual ~EMAILnotify(void){};
    > > virtual void Send(){ cout << "Send() Email: " << this << endl; }
    > >};
    > >Notification::Notification(string sNotifyType)
    > >{
    > > if(sNotifyType == "EMAIL")

    >
    > Design.
    > Don't identify types by strings (in general). Use symbolic constants
    > if you absolutely have to. But even more to the point: don't identify
    > types by data unless you really Really REALLY have to.
    >
    >
    > > pNotify = new EMAILnotify; // Causes 2nd Constructor call
    > >}
    > >Notification::~Notification(void)
    > >{
    > > if( NULL != pNotify )

    >
    > Coding.
    > No need to check for NULL.
    >
    >
    > > delete pNotify;
    > >}
    > >
    > >void main()

    >
    > C++ standard.
    > 'void main' is not allowed. This is not a valid standard C++ program.
    >
    >
    > >{
    > > Notification* pNotification = new Notification("EMAIL");
    > > pNotification->Send();
    > > delete pNotification;

    >
    > Style.
    > The above is not exception safe in any sense. Use a std::auto_ptr.
    >
    >
    > >}


    Well that was a great help, its cleared up any queries as to why the
    c'tor was being called twice!
     
    jb, Dec 11, 2003
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. mrstephengross
    Replies:
    5
    Views:
    598
    Larry I Smith
    May 18, 2005
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,999
    Smokey Grindel
    Dec 2, 2006
  3. TechCrazy
    Replies:
    5
    Views:
    398
    Karl Heinz Buchegger
    Jul 15, 2005
  4. Alexander Stippler

    conversion constructor called twice - why?

    Alexander Stippler, Oct 30, 2005, in forum: C++
    Replies:
    3
    Views:
    357
    Valentin Samko
    Oct 31, 2005
  5. ali
    Replies:
    4
    Views:
    579
    David Harmon
    Mar 5, 2007
Loading...

Share This Page