Cline/Lomow Book (Original) FAQ # 158

Discussion in 'C++' started by Tom, Dec 15, 2005.

  1. Tom

    Tom Guest

    FAQ 158 is about correct usage of OO. I am struggling to understand
    how the correct function is selected. Three derived classes from base
    class "Printer2". Where is the logic that selects from the three
    over-rides? That small decoration "p" in the next to last line of code
    seems to be the key. This rookie just doesn't 'get it'. Thanks for any
    help.

    Below is a copy of the FAQ 158 program:

    =========================================

    class Printer2 {
    public :
    virtual ~Printer2( ) { }
    virtual void italics(const char* s) = 0;
    };

    class EpsonPrinter2 : public Printer2 {
    public :
    virtual void intalics(const char* s)
    { cout << esc << "i+" << s << esc << "i-"; }
    };

    class ProprinterPrinter2 : public Printer2 {
    public :
    virtual void intalics(const char* s)
    { cout << esc << "[i" << s << esc << "[n"; }
    };

    class StarPrinter2 : public Printer2 {
    public :
    virtual void intalics(const char* s)
    { cout << esc << "x" << s << esc << "y"; }
    };

    void
    printUsingItalics ( Printer2& p, const char* s)
    {
    p.italics(s);
    }
    Tom, Dec 15, 2005
    #1
    1. Advertising

  2. Tom wrote:
    > FAQ 158 is about correct usage of OO. I am struggling to understand
    > how the correct function is selected. Three derived classes from base
    > class "Printer2". Where is the logic that selects from the three
    > over-rides? That small decoration "p" in the next to last line of code
    > seems to be the key. This rookie just doesn't 'get it'. Thanks for any
    > help.
    >
    > Below is a copy of the FAQ 158 program:
    >
    > =========================================
    >
    > class Printer2 {
    > public :
    > virtual ~Printer2( ) { }
    > virtual void italics(const char* s) = 0;
    > };
    >
    > class EpsonPrinter2 : public Printer2 {
    > public :
    > virtual void intalics(const char* s)
    > { cout << esc << "i+" << s << esc << "i-"; }
    > };
    >
    > class ProprinterPrinter2 : public Printer2 {
    > public :
    > virtual void intalics(const char* s)
    > { cout << esc << "[i" << s << esc << "[n"; }
    > };
    >
    > class StarPrinter2 : public Printer2 {
    > public :
    > virtual void intalics(const char* s)
    > { cout << esc << "x" << s << esc << "y"; }
    > };
    >
    > void
    > printUsingItalics ( Printer2& p, const char* s)
    > {
    > p.italics(s);
    > }


    Since italics is a virtual function, it is bound dynamically. In other
    words, the exact version of italics is selected from the actual class
    held by the reference p.
    Neelesh Bodas, Dec 15, 2005
    #2
    1. Advertising

  3. Tom

    marcas Guest

    Tom schrieb:
    > FAQ 158 is about correct usage of OO. I am struggling to understand
    > how the correct function is selected. Three derived classes from base
    > class "Printer2". Where is the logic that selects from the three
    > over-rides? That small decoration "p" in the next to last line of code
    > seems to be the key. This rookie just doesn't 'get it'. Thanks for any
    > help.
    >


    Hi,

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

    has a good explanation [see 20.4]

    regards marcas
    marcas, Dec 15, 2005
    #3
  4. Tom

    Tom Guest

    On 15 Dec 2005 00:22:27 -0800, "Neelesh Bodas"
    <> wrote:

    >
    >Tom wrote:
    >> FAQ 158 is about correct usage of OO. I am struggling to understand
    >> how the correct function is selected. Three derived classes from base
    >> class "Printer2". Where is the logic that selects from the three
    >> over-rides? That small decoration "p" in the next to last line of code
    >> seems to be the key. This rookie just doesn't 'get it'. Thanks for any
    >> help.
    >>
    >> Below is a copy of the FAQ 158 program:
    >>
    >> =========================================
    >>
    >> class Printer2 {
    >> public :
    >> virtual ~Printer2( ) { }
    >> virtual void italics(const char* s) = 0;
    >> };
    >>
    >> class EpsonPrinter2 : public Printer2 {
    >> public :
    >> virtual void intalics(const char* s)
    >> { cout << esc << "i+" << s << esc << "i-"; }
    >> };
    >>
    >> class ProprinterPrinter2 : public Printer2 {
    >> public :
    >> virtual void intalics(const char* s)
    >> { cout << esc << "[i" << s << esc << "[n"; }
    >> };
    >>
    >> class StarPrinter2 : public Printer2 {
    >> public :
    >> virtual void intalics(const char* s)
    >> { cout << esc << "x" << s << esc << "y"; }
    >> };
    >>
    >> void
    >> printUsingItalics ( Printer2& p, const char* s)
    >> {
    >> p.italics(s);
    >> }

    >
    >Since italics is a virtual function, it is bound dynamically. In other
    >words, the exact version of italics is selected from the actual class
    >held by the reference p.


    Thanks for the reply Neelesh. I am definately struggling in the
    transition to OO. Some of the examples within "C++ FAQs" are far more
    advanced than my current skill level. The examples I guess are not
    complete blocks of code? In particular the main( ) is missing? Your
    response made me reread chapter #23 on references and referents. (130
    pages deeper into the book. I have read it cover-to-cover and will
    have to repeatedly it seems.)

    So to make the code complete ... one needs to add something along the
    following lines?

    main ( )
    {
    StarPrinter2 p; // Creating A Derived Object
    // Of Type StarPrinter2
    char textString[] = "I have a dream to learn OO.";
    printUsingItalics( p , textString );
    }
    Tom, Dec 15, 2005
    #4
  5. Tom wrote:
    >
    > So to make the code complete ... one needs to add something along the
    > following lines?
    >
    > main ( )
    > {
    > StarPrinter2 p; // Creating A Derived Object
    > // Of Type StarPrinter2
    > char textString[] = "I have a dream to learn OO.";
    > printUsingItalics( p , textString );
    > }


    I am really not sure. IIRR, this involves a problem of "slicing". You
    are actually passing a reference to derived class, but the function
    prototype expects a reference to base class.

    Better is to do this :

    Printer2 *p = new StarPrinter2;
    char textString[] = "I have a dream to learn OO.";
    printUsingItalics( *p , textString );

    But as I said, I am not sure about this slicing thing (I know that it
    happens when you have pointers in place of references)
    Neelesh Bodas, Dec 15, 2005
    #5
  6. Tom

    Guest

    Neelesh Bodas wrote:

    > Tom wrote:
    > >
    > > So to make the code complete ... one needs to add something along the
    > > following lines?
    > >
    > > main ( )
    > > {
    > > StarPrinter2 p; // Creating A Derived Object
    > > // Of Type StarPrinter2
    > > char textString[] = "I have a dream to learn OO.";
    > > printUsingItalics( p , textString );
    > > }

    >
    > I am really not sure. IIRR, this involves a problem of "slicing". You
    > are actually passing a reference to derived class, but the function
    > prototype expects a reference to base class.


    That's not a problem. You don't get slicing when you pass by reference
    like that. You get slicing when you pass a derived object by *value* to
    a function expecting a base object. Have you ever thrown an exception
    derived from std::exception then caught a std::exception&. It works.

    > Better is to do this :
    >
    > Printer2 *p = new StarPrinter2;
    > char textString[] = "I have a dream to learn OO.";
    > printUsingItalics( *p , textString );


    Dynamic allocation and pointers are not necessary to avoid slicing. So,
    as ever, if you don't need to manually control the lifetime of the
    object, don't use dynamic allocation.

    Gavin Deane
    , Dec 15, 2005
    #6
  7. Tom

    mlimber Guest

    Neelesh Bodas wrote:
    > Tom wrote:
    > >
    > > So to make the code complete ... one needs to add something along the
    > > following lines?
    > >
    > > main ( )
    > > {
    > > StarPrinter2 p; // Creating A Derived Object
    > > // Of Type StarPrinter2
    > > char textString[] = "I have a dream to learn OO.";
    > > printUsingItalics( p , textString );
    > > }

    >
    > I am really not sure. IIRR, this involves a problem of "slicing". You
    > are actually passing a reference to derived class, but the function
    > prototype expects a reference to base class.


    Incorrect. Passing an object by value might slice it, but passing by
    pointer OR by reference will both produce correct polymorphic behavior
    and without chance of slicing. See these FAQs:

    http://www.parashift.com/c -faq-lite/value-vs-ref-semantics.html#faq-31.1
    http://www.parashift.com/c -faq-lite/value-vs-ref-semantics.html#faq-31.8

    > Better is to do this :
    >
    > Printer2 *p = new StarPrinter2;
    > char textString[] = "I have a dream to learn OO.";
    > printUsingItalics( *p , textString );
    >
    > But as I said, I am not sure about this slicing thing (I know that it
    > happens when you have pointers in place of references)


    Better at least to use std::auto_ptr (or boost::scoped_ptr,
    boost::shared_ptr, etc.) if you're going to use new. The OP's code is
    better in my opinion since it avoids dynamic allocation altogether when
    it is unnecessary.

    Cheers! --M
    mlimber, Dec 15, 2005
    #7
  8. Tom

    Artie Gold Guest

    Neelesh Bodas wrote:
    > Tom wrote:
    >
    >>So to make the code complete ... one needs to add something along the
    >>following lines?


    What are you talking about?

    Had you quoted the relevant portions of the originally supplied code,
    this would all be clearer.

    >>
    >>main ( )
    >>{
    >> StarPrinter2 p; // Creating A Derived Object
    >> // Of Type StarPrinter2

    No, it's an attempt to instantiate an abstract base class -- which you
    can't do.


    >> char textString[] = "I have a dream to learn OO.";
    >> printUsingItalics( p , textString );
    >>}

    >
    >
    > I am really not sure. IIRR, this involves a problem of "slicing". You
    > are actually passing a reference to derived class, but the function
    > prototype expects a reference to base class.
    >
    > Better is to do this :
    >
    > Printer2 *p = new StarPrinter2;


    See above.

    > char textString[] = "I have a dream to learn OO.";
    > printUsingItalics( *p , textString );
    >
    > But as I said, I am not sure about this slicing thing (I know that it
    > happens when you have pointers in place of references)
    >

    Please have *some* idea what you're doing before posting.

    HTH,
    --ag

    --
    Artie Gold -- Austin, Texas
    http://goldsays.blogspot.com (new post 8/5)
    http://www.cafepress.com/goldsays
    "If you have nothing to hide, you're not trying!"
    Artie Gold, Dec 15, 2005
    #8
  9. Artie Gold wrote:
    > What are you talking about?
    >
    > Had you quoted the relevant portions of the originally supplied code,
    > this would all be clearer.


    My reply was w.r.t. the tom's post and I just quoted the "only relavent
    portions from that". May be I quoted less, will take care in future.

    >
    > >>
    > >>main ( )
    > >>{
    > >> StarPrinter2 p; // Creating A Derived Object
    > >> // Of Type StarPrinter2

    > No, it's an attempt to instantiate an abstract base class -- which you
    > can't do.


    StartPrinter2 is a derived class, derived from the base class Printer2
    which is abstract. In other words, I am _not_ instantiating ABC - I am
    simply creating an object of a derived class.

    I believe that the confusion is due to the fact that OP has mis-spelled
    italics as intalics in all derived classes. But looking at the context,
    it was clear to me that OP actually meant italics at all these places.

    >
    >
    > >> char textString[] = "I have a dream to learn OO.";
    > >> printUsingItalics( p , textString );
    > >>}

    > >
    > >
    > > I am really not sure. IIRR, this involves a problem of "slicing". You
    > > are actually passing a reference to derived class, but the function
    > > prototype expects a reference to base class.
    > >
    > > Better is to do this :
    > >
    > > Printer2 *p = new StarPrinter2;

    >
    > See above.


    Same applies here. I am _not_ instantiating an ABC.

    > > char textString[] = "I have a dream to learn OO.";
    > > printUsingItalics( *p , textString );
    > >
    > > But as I said, I am not sure about this slicing thing (I know that it
    > > happens when you have pointers in place of references)
    > >

    > Please have *some* idea what you're doing before posting.


    OK. Thanks for that. Will remember in future.
    Neelesh Bodas, Dec 15, 2005
    #9
  10. Tom

    marcas Guest

    Artie Gold schrieb:

    >>>
    >>> main ( )
    >>> {
    >>> StarPrinter2 p; // Creating A Derived Object
    >>> // Of Type StarPrinter2

    >
    > No, it's an attempt to instantiate an abstract base class -- which you
    > can't do.
    >
    >


    Hi,

    it is true, that Printer2 is an abstract class. He makes an instance
    of StarPrinter2, which is a non abstract class due to replacemant of the
    pure virtual function. I think, that it is ok to assume that he meant
    "italics" instead of "intalics".

    regards marcas
    marcas, Dec 15, 2005
    #10
  11. Tom

    mlimber Guest

    Artie Gold wrote:
    > Neelesh Bodas wrote:
    > > Tom wrote:
    > >
    > >>So to make the code complete ... one needs to add something along the
    > >>following lines?

    >
    > What are you talking about?


    The OP doesn' understand the code snippet because it isn't a complete
    program. He's supplying what's lacking. (Or are you just noting that he
    didn't quote the whole message?)

    > Had you quoted the relevant portions of the originally supplied code,
    > this would all be clearer.
    >
    > >>
    > >>main ( )
    > >>{
    > >> StarPrinter2 p; // Creating A Derived Object
    > >> // Of Type StarPrinter2

    > No, it's an attempt to instantiate an abstract base class -- which you
    > can't do.

    [snip]

    Clearly, there was just a typo ("intalics" instead of "italics"), and
    this, as stated, is an attempt to instantiate (or, "create") a derived
    object. What's your objection, exactly?

    Cheers! --M
    mlimber, Dec 15, 2005
    #11
  12. mlimber wrote:
    > > I am really not sure. IIRR, this involves a problem of "slicing". You
    > > are actually passing a reference to derived class, but the function
    > > prototype expects a reference to base class.

    >
    > Incorrect. Passing an object by value might slice it, but passing by
    > pointer OR by reference will both produce correct polymorphic behavior
    > and without chance of slicing. See these FAQs:


    Yes you are right. Aplogoies.
    Thanks (also to deane) for pointing out. It was a silly thing on my
    part to get confused in this point.
    Neelesh Bodas, Dec 15, 2005
    #12
  13. Tom

    Artie Gold Guest

    mlimber wrote:
    > Artie Gold wrote:
    >
    >>Neelesh Bodas wrote:
    >>
    >>>Tom wrote:
    >>>
    >>>
    >>>>So to make the code complete ... one needs to add something along the
    >>>>following lines?

    >>
    >>What are you talking about?

    >
    >
    > The OP doesn' understand the code snippet because it isn't a complete
    > program. He's supplying what's lacking. (Or are you just noting that he
    > didn't quote the whole message?)
    >
    >
    >>Had you quoted the relevant portions of the originally supplied code,
    >>this would all be clearer.
    >>
    >>
    >>>>main ( )
    >>>>{
    >>>>StarPrinter2 p; // Creating A Derived Object
    >>>> // Of Type StarPrinter2

    >>
    >>No, it's an attempt to instantiate an abstract base class -- which you
    >>can't do.

    >
    > [snip]
    >
    > Clearly, there was just a typo ("intalics" instead of "italics"), and
    > this, as stated, is an attempt to instantiate (or, "create") a derived
    > object. What's your objection, exactly?
    >
    > Cheers! --M
    >


    Point taken.
    --ag

    --
    Artie Gold -- Austin, Texas
    http://goldsays.blogspot.com (new post 8/5)
    http://www.cafepress.com/goldsays
    "If you have nothing to hide, you're not trying!"
    Artie Gold, Dec 15, 2005
    #13
  14. Tom

    Tom Guest

    My many thanks to those who responded to my confusion about FAQ #158.
    I have learned more following the discussion and from the online
    references I was pointed towards. It was definitely an error on my
    part misspelling the overrides in the derived classes. There's a lot
    of very smart folks in this group. A bit intimidating for sure, but if
    I can just draft along the education will be a thrill.

    BTW - I adjusted my font size in Agent editor and maybe now I won't
    need stronger reading glasses and might catch my spelling errors more
    easily.
    Tom, Dec 16, 2005
    #14
    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. hugo2
    Replies:
    8
    Views:
    316
    hugo2
    Jul 8, 2005
  2. shuchen.
    Replies:
    0
    Views:
    425
    shuchen.
    Nov 29, 2007
  3. Kostas I.
    Replies:
    0
    Views:
    443
    Kostas I.
    Nov 29, 2007
  4. Matthew D Moss

    [QUIZ] Hello, world? (#158)

    Matthew D Moss, Mar 1, 2008, in forum: Ruby
    Replies:
    40
    Views:
    374
    Matthew Moss
    Mar 6, 2008
  5. James Koppel

    [SOLUTION] [QUIZ] Hello, world? (#158)

    James Koppel, Mar 3, 2008, in forum: Ruby
    Replies:
    0
    Views:
    85
    James Koppel
    Mar 3, 2008
Loading...

Share This Page