I need help understanding inheritance and virtual functions

Discussion in 'C++' started by dwightarmyofchampions@hotmail.com, May 7, 2009.

  1. Guest

    I'm a bit of a novice to C++ and I'm having a bit of trouble
    understanding inheritance and virtual functions. I mean I understand
    how one class can inherit a base class so you can have objects of the
    derived class inherit the base class's member functions without having
    to duplicate a whole bunch of code. But that's just timesaving, and I
    know there's a whole lot more to it than that. And I definitely don't
    understand how virtual functions can be the "single most important
    topic from an OO perspective... C++ without 'virtual' is not OO," as
    the C++ FAQ puts it. Could someone please point me to a lengthy book
    and/or website that goes really in-depth into it, and preferably with
    lots and lots of examples?
     
    , May 7, 2009
    #1
    1. Advertising

  2. Christopher Guest

    On May 6, 7:41 pm, wrote:
    > I'm a bit of a novice to C++ and I'm having a bit of trouble
    > understanding inheritance and virtual functions. I mean I understand
    > how one class can inherit a base class so you can have objects of the
    > derived class inherit the base class's member functions without having
    > to duplicate a whole bunch of code. But that's just timesaving, and I
    > know there's a whole lot more to it than that. And I definitely don't
    > understand how virtual functions can be the "single most important
    > topic from an OO perspective... C++ without 'virtual' is not OO," as
    > the C++ FAQ puts it. Could someone please point me to a lengthy book
    > and/or website that goes really in-depth into it, and preferably with
    > lots and lots of examples?


    Best example is to try it out
    The way I like to think about it is (and my explanation might be
    wrong) :
    "a derived method overides the behavior of the virtual base class
    method, _when the pointer of any type points to a derived type
    object_"
    "a derived method overides the behavior of a non virtual base class
    method, _only when called from a derived type pointer_"

    Try using each of these to call a virtual method and compare the
    behavior when you delete the virtual keyword:

    DerivedType * ptr1 = new DerivedType();
    DerivedType * ptr2 = new BaseType();
    BaseType * ptr3 = new DerivedType();
    BaseType * ptr4 = new BaseType();
     
    Christopher, May 7, 2009
    #2
    1. Advertising

  3. Tim Love Guest

    writes:

    >Could someone please point me to a lengthy book
    >and/or website that goes really in-depth into it, and preferably with
    >lots and lots of examples?


    I can offer a standard example. The program has a list of shapes which need
    redrawing. Each type of object has its own draw routine.
    Compile the code below as is, run it, then add the word "virtual" as
    indicated and compile+run again.


    #include <iostream>
    using namespace std;

    class Point {
    public:
    float x;
    float y;
    };

    class Shape {
    public:
    // Try adding "virtual" to the front of the next line.
    void draw() { cout << "Shape's draw routine\n";} ;
    // Note that replacing the above line by
    // "virtual void draw()=0;" should force derived classes to
    // have draw() routines. See if this is true.
    float area;
    };

    class Triangle: public Shape {
    Point points[3];
    void draw() { cout << "Triangle's draw routine\n";} ;
    };

    class Rectangle: public Shape {
    Point points[4];
    void draw() { cout << "Rectangle's draw routine\n";} ;
    };


    int main() {

    Triangle t1, t2;
    Rectangle r1, r2;

    Shape* shapes[4];
    shapes[0]=&t1;
    shapes[1]=&r1;
    shapes[2]=&t2;
    shapes[3]=&r2;

    for (int i=0;i<4; i++)
    shapes->draw();
    }
     
    Tim Love, May 7, 2009
    #3
  4. Guest

    I compiled the program, both with and without the virtual keyowrd, but
    I still don't quite get it.

    How can the derived class override the base class's virtual draw()
    function if you're defining an object of type Shape*? The derived
    classes have things that the base classes do not (additional data
    members and such), and now even though it's an object of type Shape*
    (the base class), it can still behave like an object of the derived
    class (i.e., accessing its derived draw() function)? And if that is
    the case, why not just originally define the object to be of type
    Derived* in the first place?

    Shape* shapes[4];
    shapes[0]=&t1;
    shapes[1]=&r1;
    shapes[2]=&t2;
    shapes[3]=&r2;

    ^^^ Can you give a more detailed explanation as to what exactly is
    going on here?
     
    , May 7, 2009
    #4
  5. Neelesh Guest

    On May 8, 3:14 am, wrote:
    > I compiled the program, both with and without the virtual keyowrd, but
    > I still don't quite get it.
    >

    Which program? It is always a good idea to keep the relevant context
    of the original thread intact while you reply to it - it helps many
    time.

    [original thread]
    class Shape{ public: virtual void draw(); };
    class Rectangle: public Shape { public: virtual void draw(); };
    class Triangle: public Shape { public: virtual void draw(); };

    int main() {

    Triangle t1, t2;
    Rectangle r1, r2;

    Shape* shapes[4];
    shapes[0]=&t1;
    shapes[1]=&r1;
    shapes[2]=&t2;
    shapes[3]=&r2;
    }

    [/end original thread]

    > How can the derived class override the base class's virtual draw()
    > function if you're defining an object of type Shape*?


    You are _not_ defining an object of type Shape*. you are defining a
    variable "shapes" that represents an Array of four Shape-pointers.
    What is important here is to understand that the "shapes" array
    doesn't itself contain Shape objects, rather it container four
    pointers.

    > The derived
    > classes have things that the base classes do not (additional data
    > members and such), and now even though it's an object of type Shape*
    > (the base class), it can still behave like an object of the derived
    > class (i.e., accessing its derived draw() function)?


    The object that is pointed by shapes[0], or shapes[1] etc is an object
    of derived class. This is because we are clearly saying

    shapes[0] = &t1; //t1 is a triangle object, and address of this
    object is held by shapes[0]
    Similarly
    shapes[1] = &r1; //r1 is a rectangle object.

    > And if that is
    > the case, why not just originally define the object to be of type
    > Derived* in the first place?
    >

    Please understand again: Objects don't have types like "Derived*" or
    "Base*" , they are the types of "pointers". Also, please note the
    difference between a pointer, and an object. When we say

    Shape* s = new Triangle();

    We are creating an object of type Triangle (on heap), we are creating
    a pointer of type Shape* (on stack) and we are putting the address of
    the newly created Triangle object in the newly created Shape*
    pointer.

    >[...]
     
    Neelesh, May 8, 2009
    #5
  6. wrote:
    > why not just originally define the object to be of type
    > Derived* in the first place?


    I think the C++ streams are a perfect example of object-oriented
    programming (including dynamic binding, ie. virtual functions) in
    action. For example, suppose you have a function like this:

    void printSomethingTo(std::eek:stream& os)
    {
    os << "Something";
    }

    std::eek:stream is a *base class* from which several other types of
    stream classes have been derived. The printSomethingTo() function above
    takes a reference of this base class type, but doesn't really know what
    it's really given. However, it doesn't have to: It can still output the
    string to whatever it was given, as long as it has been derived from
    that base class.

    The idea is that you can give it *different* types of objects as
    parameter, and it will work with all of them. Example:

    std::eek:fstream outputFile("somefile.txt");
    printSomethingto(outputFile); // prints to a file

    std::eek:stringstream aStringStream;
    printSomethingTo(aStringStream); // prints to memory

    printSomethingTo(std::cout); // prints to standard output

    Note that the printSomethingTo() function is compiled only once, and
    exists only once in the program. It's *not* compiled again for each
    possible type it's given as parameter. (printSomethingTo() might even be
    eg. in a precompiled library, and in the program itself you don't even
    see how it has been implemented.) Yet still the above works: The
    function is able to output the string to different targets without
    problems. That's dynamic binding (ie. virtual functions) in action.
     
    Juha Nieminen, May 8, 2009
    #6
  7. Tim Love Guest

    writes:

    >I compiled the program, both with and without the virtual keyowrd, but
    >I still don't quite get it.


    > How can the derived class override the base class's virtual draw()
    > function if you're defining an object of type Shape*?

    As others have said, your terminology's not quite right but yes, this
    is the crux of the issue.

    Without "virtual", a thing pointed to by a Shape* pointer is
    treated as a Shape. With "virtual", the thing pointed to by a
    Shape* pointer is dealt with according to what it "really" is.

    The shapes array in the example is the kind of thing that a
    drawing package might use when items are grouped.
    With "virtual" you get the best of both worlds - the top-level code
    doesn't have to worry about unnecessary detail (if a new type of shape
    is added to the code, the top-level code won't need to be changed) and each
    type of shape retains its individuality - each can have its own draw()
    member function (objects are best-place to do that job - they "know" about
    themselves).
     
    Tim Love, May 8, 2009
    #7
  8. James Kanze Guest

    On May 8, 10:29 am, Juha Nieminen <> wrote:
    > wrote:
    > > why not just originally define the object to be of type
    > > Derived* in the first place?


    > I think the C++ streams are a perfect example of
    > object-oriented programming (including dynamic binding, ie.
    > virtual functions) in action.


    Actually, they are a masterful example of using the most
    appropriate technique to support customization, depending on the
    type of customization desired. They use polymorphism for one
    type of customization, and function overloading for the other.

    > For example, suppose you have a function like this:


    > void printSomethingTo(std::eek:stream& os)
    > {
    > os << "Something";
    > }


    > std::eek:stream is a *base class* from which several other types
    > of stream classes have been derived. The printSomethingTo()
    > function above takes a reference of this base class type, but
    > doesn't really know what it's really given. However, it
    > doesn't have to: It can still output the string to whatever it
    > was given, as long as it has been derived from that base
    > class.


    Yes, but that's not really a good example, because the functions
    involved aren't virtual, and may not even be members. The
    important point is that when the ostream, here, decides to
    output a character, it calls a virtual function in the
    associated streambuf. Which then does whatever is appropriate.
    (It's actually a bit more complicated than that, because the
    base class, streambuf, is more than just an interface; it uses
    the template method pattern to customize its action, only
    calling the virtual function when it has no room in its buffer.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 8, 2009
    #8
  9. Guest

    Thanks for all the responses, everybody. And this is all good, but
    like I said, is there a big massive book or chapter that explains this
    concept in much greater detail?
     
    , May 10, 2009
    #9
  10. wrote:

    > Thanks for all the responses, everybody. And this is all good, but
    > like I said, is there a big massive book or chapter that explains this
    > concept in much greater detail?


    I can't recommend a specific book, but it seems you need a good
    beginners book on OOA/OOD/OOP (Object Oriented Analysis / Design /
    Programming). This topic is not specific to any particular language, so
    look also for books that appear to be language agnostic or (if you don't
    mind learning a different language before coming back to C++) use
    another language for their code examples.

    The people over in news:comp.object might also be able to give you some
    book recommendations.

    Bart v Ingen Schenau
    --
    a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
    c.l.c FAQ: http://c-faq.com/
    c.l.c++ FAQ: http://www.parashift.com/c -faq-lite/
     
    Bart van Ingen Schenau, May 11, 2009
    #10
    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:
    19
    Views:
    829
    Daniel T.
    Feb 4, 2004
  2. cppsks
    Replies:
    0
    Views:
    854
    cppsks
    Oct 27, 2004
  3. Ashwin
    Replies:
    2
    Views:
    367
    Pierre Barbier de Reuille
    Aug 1, 2006
  4. John Goche
    Replies:
    10
    Views:
    797
    Marcus Kwok
    Dec 8, 2006
  5. Replies:
    3
    Views:
    302
Loading...

Share This Page