virtual functions and destructors (newbie)

Discussion in 'C++' started by Peter, Oct 13, 2005.

  1. Peter

    Peter Guest

    I *think* I understand the need for virtual functions. If you call a method
    defined in Base, that method has no way of knowing about an overridden
    functions in Derived.

    Somehow, virtual functions allow methods in Base to "know" about other
    functions that are redefined in Derived.



    Now I'm trying to understand the need for virtual destructors. In this code:

    #include <iostream>
    using namepaste std;

    class Base
    {
    public:
    Base() { cout << "Constructor: Base" << endl; }
    ~Base(){ cout << "Destructor : Base" << endl; }
    };

    class Derived: public Base
    {
    public:
    Derived() { cout << "Constructor: Derived" << endl; }
    ~Derived(){ cout << "Destructor : Derived" << endl; }
    };

    int main(void)
    {
    Base *Var = new Derived();
    delete Var;
    return 0;
    }

    the derived destructor is not called, and this is fixed by declaring the base
    destructor virtual.

    Unfortunately, this is an unsatisfying explanation: I don't understand why
    the derived destructor isn't being called. I could certainly have a function
    named foo() in both Base and Derived, and if I used:

    Var->foo();

    I would get Derived::foo(), not Base::foo().

    So my first question is, why the difference? It seems more natural for
    "delete Var" to call Derived::~Derived, not Base::~Base. After all, Var is
    of type pointer to Derived, not pointer to Base. So _why_ is ~Derived() not
    called in this case?



    Secondly, there seems to be a disconnect between virtual functions and
    virtual destructors.

    Virtual functions help Base functions know about functions that are redefined
    in Derived. In other words, to help old code know about new code.

    Virtual destructors seem to help the Derived class know about its own
    destructor.

    I'm getting a flashback from when I was trying to sort out the many uses for
    the word "static". Is there some common logical connection that explains why
    we use the word "virtual" to do these seemingly two very different tasks?


    Thanks!
    Pete
    Peter, Oct 13, 2005
    #1
    1. Advertising

  2. Peter wrote:
    > Now I'm trying to understand the need for virtual destructors. In this code:
    >
    > #include <iostream>
    > using namepaste std;
    >
    > class Base
    > {
    > public:
    > Base() { cout << "Constructor: Base" << endl; }
    > ~Base(){ cout << "Destructor : Base" << endl; }
    > };
    >
    > class Derived: public Base
    > {
    > public:
    > Derived() { cout << "Constructor: Derived" << endl; }
    > ~Derived(){ cout << "Destructor : Derived" << endl; }
    > };
    >
    > int main(void)
    > {
    > Base *Var = new Derived();
    > delete Var;
    > return 0;
    > }
    >
    > the derived destructor is not called, and this is fixed by declaring the base
    > destructor virtual.
    >
    > Unfortunately, this is an unsatisfying explanation: I don't understand why
    > the derived destructor isn't being called.


    Could it be because the destructor is not virtual?

    > I could certainly have a function
    > named foo() in both Base and Derived, and if I used:
    >
    > Var->foo();
    >
    > I would get Derived::foo(), not Base::foo().


    You would? Really??? Do, please, humour me, try it.

    > So my first question is, why the difference?


    There is none.

    > It seems more natural for
    > "delete Var" to call Derived::~Derived, not Base::~Base. After all, Var is
    > of type pointer to Derived, not pointer to Base. So _why_ is ~Derived() not
    > called in this case?


    Dare I repeat myself? Because it's not virtual.

    > Secondly, there seems to be a disconnect between virtual functions and
    > virtual destructors.


    Really???

    > Virtual functions help Base functions know about functions that are redefined
    > in Derived.


    No.

    > In other words, to help old code know about new code.


    No, not exactly.

    > Virtual destructors seem to help the Derived class know about its own
    > destructor.


    Huh?

    > I'm getting a flashback from when I was trying to sort out the many uses for
    > the word "static". Is there some common logical connection that explains why
    > we use the word "virtual" to do these seemingly two very different tasks?


    No. 'virtual' has only one overload: inheritance can be virtual and it
    means slightly different thing than 'virtual' in functions. 'static' has
    _four_ overloads.

    V
    Victor Bazarov, Oct 13, 2005
    #2
    1. Advertising

  3. Peter

    Rolf Magnus Guest

    Peter wrote:

    > int main(void)
    > {
    > Base *Var = new Derived();
    > delete Var;
    > return 0;
    > }


    [snip]

    > Unfortunately, this is an unsatisfying explanation: I don't understand why
    > the derived destructor isn't being called. I could certainly have a
    > function named foo() in both Base and Derived, and if I used:
    >
    > Var->foo();
    >
    > I would get Derived::foo(), not Base::foo().


    No, you woldn't. You'd get Base::foo().

    > So my first question is, why the difference?


    There is no difference.

    > It seems more natural for "delete Var" to call Derived::~Derived, not
    > Base::~Base. After all, Var is of type pointer to Derived, not pointer to
    > Base.


    Above, you wrote 'Base *Var', so Var is a pointer to Base.

    > Secondly, there seems to be a disconnect between virtual functions and
    > virtual destructors.
    >
    > Virtual functions help Base functions know about functions that are
    > redefined in Derived. In other words, to help old code know about new
    > code.
    >
    > Virtual destructors seem to help the Derived class know about its own
    > destructor.


    A virtual function helps the compiler find out which function to call
    without knowing the actual type of the object. Similarly, a virtual
    destructor helps finding which destructor to call without knowing the
    actual type of the object.

    > I'm getting a flashback from when I was trying to sort out the many uses
    > form the word "static".


    Static has indeed several different meanings, though with a bit of
    abstraction, you can reduce that number to two or so.
    Rolf Magnus, Oct 13, 2005
    #3
  4. Peter

    Marcus Kwok Guest

    Marcus Kwok, Oct 13, 2005
    #4
  5. Peter

    mlimber Guest

    Peter wrote:
    > I *think* I understand the need for virtual functions. If you call a method
    > defined in Base, that method has no way of knowing about an overridden
    > functions in Derived.
    >
    > Somehow, virtual functions allow methods in Base to "know" about other
    > functions that are redefined in Derived.


    More accurately, virtual functions allow the user to override the
    behavior of the base class.

    You can also declare abstract classes that have one or more pure
    virtual functions, i.e., functions that have no body in the base class
    and MUST be defined by a subclass (or a subsubclass, etc.) in order to
    be instantiated. This is useful for establishing interfaces. For
    instance, assume we have a Document and Clipboard class defined for a
    standard text editor. Then we can establish a command processing scheme
    like this:

    struct Command
    {
    virtual ~Command() {} // Empty virtual destructor (see below)
    virtual void Execute() = 0; // pure virtual
    };

    struct CopyCommand : public Command
    {
    CopyCommand( Document& doc, Clipboard& clip )
    : doc_(doc), clip_(clip)
    {}

    virtual void Execute()
    {
    clip_.SetText( doc_.GetSelection() );
    }

    protected:
    Document& doc_;
    Clipboard& clip_;
    };

    struct CutCommand : public CopyCommand
    {
    CutCommand( Document& doc, Clipboard& clip )
    : CopyCommand( doc, clip )
    {}

    void Execute()
    {
    CopyCommand::Execute();
    doc_.DeleteSelection();
    }
    };

    struct PasteCommand : public Command
    {
    CutCommand( Document& doc, Clipboard& clip )
    : doc_(doc), clip_(clip)
    {}

    void Execute()
    {
    doc_.InsertText( clip_.GetText() );
    }

    private:
    Document& doc_;
    Clipboard& clip_;
    };

    struct MoveCursorCommand : public Command
    {
    MoveCursorCommand( Document& doc, int lines )
    : doc_( doc ), lines_(lines)
    {}

    void Execute()
    {
    doc_.MoveCursor( lines_ );
    }

    private:
    Document& doc_;
    int lines_;
    };

    Now we can do a number of things like queue up commands for later
    execution:

    void CopyAndPasteThrice( Document& doc, Clipboard& clip )
    {
    std::vector<Cmd*> cmds;
    cmds.push_back( new CopyCommand( doc, clip ) );
    cmds.push_back( new MoveCursorCommand( doc, 2 ) );
    cmds.push_back( new PasteCommand( doc, clip ) );
    cmds.push_back( new MoveCursorCommand( doc, 2 ) );
    cmds.push_back( new PasteCommand( doc, clip ) );
    cmds.push_back( new MoveCursorCommand( doc, 2 ) );
    cmds.push_back( new PasteCommand( doc, clip ) );

    // ...

    // Execute our command queue
    typedef std::vector::iterator it;
    for( it cmd = cmds.begin(); cmd != cmds.end(); ++cmd )
    {
    cmd->Execute();
    }

    // ... Don't forget to delete the commands
    }

    Notice that we can use all commands with the same interface (namely,
    the Execute function) without knowing the specific derived type of the
    object. We can also delete them uniformly since the destructor of
    Command is also virtual. The key is that we know only that each is a
    Command and can Execute, not what the command specifically does.

    >
    >
    >
    > Now I'm trying to understand the need for virtual destructors. In this code:
    >
    > #include <iostream>
    > using namepaste std;
    >
    > class Base
    > {
    > public:
    > Base() { cout << "Constructor: Base" << endl; }
    > ~Base(){ cout << "Destructor : Base" << endl; }
    > };
    >
    > class Derived: public Base
    > {
    > public:
    > Derived() { cout << "Constructor: Derived" << endl; }
    > ~Derived(){ cout << "Destructor : Derived" << endl; }
    > };
    >
    > int main(void)
    > {
    > Base *Var = new Derived();
    > delete Var;
    > return 0;
    > }
    >
    > the derived destructor is not called, and this is fixed by declaring the base
    > destructor virtual.
    >
    > Unfortunately, this is an unsatisfying explanation: I don't understand why
    > the derived destructor isn't being called. I could certainly have a function
    > named foo() in both Base and Derived, and if I used:
    >
    > Var->foo();
    >
    > I would get Derived::foo(), not Base::foo().


    Only if foo were declared virtual. If it's not, you'd get Base::foo.

    >
    > So my first question is, why the difference? It seems more natural for
    > "delete Var" to call Derived::~Derived, not Base::~Base. After all, Var is
    > of type pointer to Derived, not pointer to Base. So _why_ is ~Derived() not
    > called in this case?


    Consider:

    struct Base
    {
    virtual ~Base();
    virtual void Foo();
    void Bar();
    };

    struct Derived : public Base
    {
    ~Derived();
    void Foo();
    void Bar(); // hides Base::Bar()
    };

    If a member function is not virtual, normal function calls take place:

    void f( Base* b )
    {
    b->Foo(); // Calls Base::Foo() if b points to a Base object
    // or Derived::Foo() if b points to a Derived object

    b->Bar(); // Calls Base::Bar() even if b points to a Derived object

    delete b; // Calls Base::~Base() if b points to a Base object
    // or Derived::~Derived() if b points to a Derived object
    }

    Essentially what happens is that a table of virtual functions is
    established in every object with a base class of type Base. The table
    holds the address of the virtual (and only virtual) functions for the
    current object. If the object is of type Base, then the virtual table
    holds the address of Base::Foo. If the object is of type Derived, then
    the table holds the address of Derived::Foo. If the function is
    virtual, the correct address is looked up in the table in order to make
    the call (hence the [spurious] complaint that virtual calls drastically
    slow programs down because of an additional indirection).

    The same is true of the destructor, and therefore you should usually
    write (possibly empty) virtual destructors in classes that have virtual
    functions. See this FAQ:

    http://www.parashift.com/c -faq-lite/virtual-functions.html#faq-20.7

    >
    >
    >
    > Secondly, there seems to be a disconnect between virtual functions and
    > virtual destructors.
    >
    > Virtual functions help Base functions know about functions that are redefined
    > in Derived. In other words, to help old code know about new code.
    >
    > Virtual destructors seem to help the Derived class know about its own
    > destructor.
    >
    > I'm getting a flashback from when I was trying to sort out the many uses for
    > the word "static". Is there some common logical connection that explains why
    > we use the word "virtual" to do these seemingly two very different tasks?


    No, the use of the virtual keyword is uniform between the two.

    Cheers! --M
    mlimber, Oct 13, 2005
    #5
  6. Peter

    Peter_Julian Guest

    "Peter" <> wrote in message
    news:dill79$5mv$...
    | I *think* I understand the need for virtual functions. If you call a
    method
    | defined in Base, that method has no way of knowing about an overridden
    | functions in Derived.
    |
    | Somehow, virtual functions allow methods in Base to "know" about other
    | functions that are redefined in Derived.

    The "somehow" is better explained when you consider that a class or
    struct with at least one virtual function implies a virtual table. The
    vtable is created at compile time and populated at runtime.

    The vtable essentially lets the instance itself track or know whether
    its a base or derived instance in a class hierarchy.

    |
    | Now I'm trying to understand the need for virtual destructors. In
    this code:
    |
    <snip>
    |
    | the derived destructor is not called, and this is fixed by declaring
    the base
    | destructor virtual.

    The reason the non-virtual derived d~tor is not called is because no
    vtable exists in the class hierarchy. A virtual d~tor implies a
    populated vtable.

    |
    | Unfortunately, this is an unsatisfying explanation: I don't understand
    why
    | the derived destructor isn't being called. I could certainly have a
    function
    | named foo() in both Base and Derived, and if I used:
    |
    | Var->foo();
    |
    | I would get Derived::foo(), not Base::foo().

    No, you'ld get Base::foo() unless you declared Base::foo() as virtual.
    The same applies to d~tors. Think vtable again.

    |
    | So my first question is, why the difference? It seems more natural
    for
    | "delete Var" to call Derived::~Derived, not Base::~Base. After all,
    Var is
    | of type pointer to Derived, not pointer to Base. So _why_ is
    ~Derived() not
    | called in this case?

    What? Var is a pointer to Base. And ~Derived can't be invoked since the
    base's d~tor is not virtual. In other words, Var has no mechanism that
    allows it to determine whether its a base or derived object.

    |
    | Secondly, there seems to be a disconnect between virtual functions and
    | virtual destructors.

    No, that's incorrect. Just because you have a pointer to a Base element
    does not mean you have a pure Base object. As an example: Var in your
    code could be either a Base or any derivation thereof. Without the
    virtual mechanism, the instance at Var has no way to determine what type
    of object it actually is (base or derived).

    |
    | Virtual functions help Base functions know about functions that are
    redefined
    | in Derived. In other words, to help old code know about new code.

    I disagree, its not "old code". Rather, it's "pertinent" code. A duck, a
    pigeon and a chicken all talk in their own way. Yet all these are birds
    and all of them can talk. Each type of bird talks in their own distinct
    way. Imagine a cage of 3 birds, one of each type. Instead of having the
    cage make the birds talk, you are basicly telling each bird to talk in
    whatever way they can. Its the bird, not the pointers, that do the
    talking. Thats the paradigm shift.

    |
    | Virtual destructors seem to help the Derived class know about its own
    | destructor.
    |
    | I'm getting a flashback from when I was trying to sort out the many
    uses for
    | the word "static". Is there some common logical connection that
    explains why
    | we use the word "virtual" to do these seemingly two very different
    tasks?

    Static is an entirely seperate issue.
    The keyword virtual is how C++ provides the instance of some
    type-hierachy to know whether its a base class, a derived class or a
    grandchild(etc...). More precisely, virtual generates the vtable which
    artificially allows an object, or instance, to be self-aware and
    self-destroyable.

    And the rule is: if you are planning to use base pointers to store
    instances of a given class hierarchy, you need virtual destructors. In
    other words, all the d~tors below are automatically virtual to satisfy
    that requirement. This is so even though only the base d~tor ~A() is
    declared as virtual.

    A
    {
    A() { }
    virtual ~A() { }
    };

    B : public A
    {
    B() { }
    ~B() { } // virtual
    };

    C : public B
    {
    C() { }
    ~C() { } // virtual
    };

    int main()
    {
    A* p = new C;
    delete p; // its the instance at p that knows what type
    // it actually is.
    // The pointer p doesn't care nor need to know.
    }

    sequence:
    A()
    B()
    C()
    ....
    ~C() // all d~tors are virtual
    ~B()
    ~A()
    Peter_Julian, Oct 14, 2005
    #6
  7. Peter

    Guest

    We know the use of virtual functions. Its main use is to implementing
    the overriding concept. That is Functions that are defined in the Base
    class, Then we redefined in the derived class.
    If we are using virtual keyword in the Base class.

    Then it will create one virtual table related to Base class.

    But later how it points to either Base class or derived Class.




    Peter_Julian wrote:
    > "Peter" <> wrote in message
    > news:dill79$5mv$...
    > | I *think* I understand the need for virtual functions. If you call a
    > method
    > | defined in Base, that method has no way of knowing about an overridden
    > | functions in Derived.
    > |
    > | Somehow, virtual functions allow methods in Base to "know" about other
    > | functions that are redefined in Derived.
    >
    > The "somehow" is better explained when you consider that a class or
    > struct with at least one virtual function implies a virtual table. The
    > vtable is created at compile time and populated at runtime.
    >
    > The vtable essentially lets the instance itself track or know whether
    > its a base or derived instance in a class hierarchy.
    >
    > |
    > | Now I'm trying to understand the need for virtual destructors. In
    > this code:
    > |
    > <snip>
    > |
    > | the derived destructor is not called, and this is fixed by declaring
    > the base
    > | destructor virtual.
    >
    > The reason the non-virtual derived d~tor is not called is because no
    > vtable exists in the class hierarchy. A virtual d~tor implies a
    > populated vtable.
    >
    > |
    > | Unfortunately, this is an unsatisfying explanation: I don't understand
    > why
    > | the derived destructor isn't being called. I could certainly have a
    > function
    > | named foo() in both Base and Derived, and if I used:
    > |
    > | Var->foo();
    > |
    > | I would get Derived::foo(), not Base::foo().
    >
    > No, you'ld get Base::foo() unless you declared Base::foo() as virtual.
    > The same applies to d~tors. Think vtable again.
    >
    > |
    > | So my first question is, why the difference? It seems more natural
    > for
    > | "delete Var" to call Derived::~Derived, not Base::~Base. After all,
    > Var is
    > | of type pointer to Derived, not pointer to Base. So _why_ is
    > ~Derived() not
    > | called in this case?
    >
    > What? Var is a pointer to Base. And ~Derived can't be invoked since the
    > base's d~tor is not virtual. In other words, Var has no mechanism that
    > allows it to determine whether its a base or derived object.
    >
    > |
    > | Secondly, there seems to be a disconnect between virtual functions and
    > | virtual destructors.
    >
    > No, that's incorrect. Just because you have a pointer to a Base element
    > does not mean you have a pure Base object. As an example: Var in your
    > code could be either a Base or any derivation thereof. Without the
    > virtual mechanism, the instance at Var has no way to determine what type
    > of object it actually is (base or derived).
    >
    > |
    > | Virtual functions help Base functions know about functions that are
    > redefined
    > | in Derived. In other words, to help old code know about new code.
    >
    > I disagree, its not "old code". Rather, it's "pertinent" code. A duck, a
    > pigeon and a chicken all talk in their own way. Yet all these are birds
    > and all of them can talk. Each type of bird talks in their own distinct
    > way. Imagine a cage of 3 birds, one of each type. Instead of having the
    > cage make the birds talk, you are basicly telling each bird to talk in
    > whatever way they can. Its the bird, not the pointers, that do the
    > talking. Thats the paradigm shift.
    >
    > |
    > | Virtual destructors seem to help the Derived class know about its own
    > | destructor.
    > |
    > | I'm getting a flashback from when I was trying to sort out the many
    > uses for
    > | the word "static". Is there some common logical connection that
    > explains why
    > | we use the word "virtual" to do these seemingly two very different
    > tasks?
    >
    > Static is an entirely seperate issue.
    > The keyword virtual is how C++ provides the instance of some
    > type-hierachy to know whether its a base class, a derived class or a
    > grandchild(etc...). More precisely, virtual generates the vtable which
    > artificially allows an object, or instance, to be self-aware and
    > self-destroyable.
    >
    > And the rule is: if you are planning to use base pointers to store
    > instances of a given class hierarchy, you need virtual destructors. In
    > other words, all the d~tors below are automatically virtual to satisfy
    > that requirement. This is so even though only the base d~tor ~A() is
    > declared as virtual.
    >
    > A
    > {
    > A() { }
    > virtual ~A() { }
    > };
    >
    > B : public A
    > {
    > B() { }
    > ~B() { } // virtual
    > };
    >
    > C : public B
    > {
    > C() { }
    > ~C() { } // virtual
    > };
    >
    > int main()
    > {
    > A* p = new C;
    > delete p; // its the instance at p that knows what type
    > // it actually is.
    > // The pointer p doesn't care nor need to know.
    > }
    >
    > sequence:
    > A()
    > B()
    > C()
    > ...
    > ~C() // all d~tors are virtual
    > ~B()
    > ~A()
    , Oct 26, 2005
    #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. qazmlp
    Replies:
    7
    Views:
    480
    Howard
    Jul 27, 2004
  2. heted7
    Replies:
    33
    Views:
    1,016
    Chris Dearlove
    May 12, 2005
  3. Replies:
    3
    Views:
    365
    Nitin Motgi
    Jan 31, 2006
  4. Pravesh
    Replies:
    3
    Views:
    325
    Pravesh
    Jun 20, 2006
  5. Henrik Goldman
    Replies:
    6
    Views:
    586
    terminator
    Nov 19, 2006
Loading...

Share This Page