need virtual behavior for friend operator<<()

Discussion in 'C++' started by noone, Jan 23, 2007.

  1. noone

    noone Guest

    hi.

    I don't use exceptions much in the embedded world, but for my plugin
    interface to a hardware MPEG encoder I'd like to, since there are so many
    places that the crummy kernel driver can do bad things to my userland
    program. I hope this news client doesn't reformat my example below and
    make it impossible to read. :^)

    consider the following exception heirarchy

    // ----------------------------

    struct base {
    string message;
    base(const char* mess): message(mess) {}
    friend ostream& operator<<(ostream& s, base& r) {
    s << r.message;
    return s;
    }
    virtual const char* is_a() { return "base"; }
    };

    // ------------------------

    struct derived: public base {
    string method;
    derived(const char* m, const char* f=""):
    base(m), method(f) {}
    const char* is_a() { return "derived"; }
    friend ostream& operator<<(ostream& s, derived& r) {
    s << r.message;
    if (r.method.length()) s << " in " << r.method;
    return s;
    };


    int main() {
    try {
    throw derived("in try block","main()");
    }
    catch(base& b)
    { cout << b.is_a() << " " << b << endl; };
    // previous line does b.is_a() virtual correctly
    // but uses friend operator<<() from base instead of
    // from derived

    return 0;
    }


    I want a generic catch block that catches the superclass of my exceptions
    and correctly binds to the class that really threw the exception. I know
    that I could make a virtual output() method for each derived class and
    output << b.output() but is there an elegant way to do this without
    adding another virtual into each derived class?

    in the past I've tried overloading the redirect operators within the
    classes but never had any luck. I've only ever been able to make them
    work well as friend methods and I don't believe a virtual friend would
    exist...Ever have a virtual friend as a kid?

    I hope I'm clearly explaining, and I anticipate some interesting
    comments on this one. :^)
     
    noone, Jan 23, 2007
    #1
    1. Advertising

  2. noone

    noone Guest

    I was afraid of this...the blasted news client joined some lines.

    I'll try to fix them below




    On Mon, 22 Jan 2007 22:26:16 -0500, noone wrote:

    > hi.
    >
    > I don't use exceptions much in the embedded world, but for my plugin
    > interface to a hardware MPEG encoder I'd like to, since there are so many
    > places that the crummy kernel driver can do bad things to my userland
    > program. I hope this news client doesn't reformat my example below and
    > make it impossible to read. :^)
    >
    > consider the following exception heirarchy
    >
    > // ----------------------------
    >
    > struct base {
    > string message;
    > base(const char* mess): message(mess) {}
    > friend ostream& operator<<(ostream& s, base& r) {
    > s << r.message;
    > return s;
    > }
    > virtual const char* is_a() { return "base"; }
    > };
    >
    > // ------------------------
    >
    > struct derived: public base {
    > string method;
    > derived(const char* m, const char* f=""):
    > base(m), method(f) {}
    > const char* is_a() { return "derived"; }
    > friend ostream& operator<<(ostream& s, derived& r) {
    > s << r.message;
    > if (r.method.length()) s << " in " << r.method; return s;
    > };
    >
    >
    > int main() {
    > try {
    > throw derived("in try block","main()");
    > }
    > catch(base& b)
    > { cout << b.is_a() << " " << b << endl; };
    > // previous line does b.is_a() virtual correctly
    > // but uses friend operator<<() from base instead of
    > // from derived
    >
    > return 0;
    > }
    > }
    >
    > I want a generic catch block that catches the superclass of my exceptions
    > and correctly binds to the class that really threw the exception. I know
    > that I could make a virtual output() method for each derived class and
    > output << b.output() but is there an elegant way to do this without
    > adding another virtual into each derived class?
    >
    > in the past I've tried overloading the redirect operators within the
    > classes but never had any luck. I've only ever been able to make them
    > work well as friend methods and I don't believe a virtual friend would
    > exist...Ever have a virtual friend as a kid?
    >
    > I hope I'm clearly explaining, and I anticipate some interesting comments
    > on this one. :^)
     
    noone, Jan 23, 2007
    #2
    1. Advertising

  3. noone

    Michael Guest

    noone wrote:
    > consider the following exception heirarchy
    >
    > // ----------------------------
    >
    > struct base {
    > string message;
    > base(const char* mess): message(mess) {}
    > friend ostream& operator<<(ostream& s, base& r) {
    > s << r.message;
    > return s;
    > }
    > virtual const char* is_a() { return "base"; }
    > };
    >
    > // ------------------------
    >
    > struct derived: public base {
    > string method;
    > derived(const char* m, const char* f=""):
    > base(m), method(f) {}
    > const char* is_a() { return "derived"; }
    > friend ostream& operator<<(ostream& s, derived& r) {
    > s << r.message;
    > if (r.method.length()) s << " in " << r.method;
    > return s;
    > };
    >
    >
    > int main() {
    > try {
    > throw derived("in try block","main()");
    > }
    > catch(base& b)
    > { cout << b.is_a() << " " << b << endl; };
    > // previous line does b.is_a() virtual correctly
    > // but uses friend operator<<() from base instead of
    > // from derived
    >
    > return 0;
    > }
    >
    >
    > I want a generic catch block that catches the superclass of my exceptions
    > and correctly binds to the class that really threw the exception. I know
    > that I could make a virtual output() method for each derived class and
    > output << b.output() but is there an elegant way to do this without
    > adding another virtual into each derived class?
    >
    > in the past I've tried overloading the redirect operators within the
    > classes but never had any luck. I've only ever been able to make them
    > work well as friend methods and I don't believe a virtual friend would
    > exist...Ever have a virtual friend as a kid?


    Here's how I've solved this in the past:

    1) Create a virtual method 'output,' as you suggested
    virtual ostream& output(ostream& s) const;

    I forget whether I had to make it public, or could make it protected.

    2) Implement it for each of the classes.

    3) For your base class (only), implement the << operator, in terms of
    output:
    friend ostream& operator<<(ostream& s, const base& b) {
    return b.output(s);
    };

    Then any/all clients of the class can just do something like:
    cout << my_instance;

    It seems a little yucky, but the yuckiness is localized to your
    exception hierarchy, the code that uses it is clean.

    Michael
     
    Michael, Jan 23, 2007
    #3
  4. noone

    noone Guest

    On Mon, 22 Jan 2007 20:54:05 -0800, Michael wrote:

    > Here's how I've solved this in the past:
    >
    > 1) Create a virtual method 'output,' as you suggested virtual ostream&
    > output(ostream& s) const;


    Yes. I was hoping to avoid this but you are confirming my suspicions

    >
    > I forget whether I had to make it public, or could make it protected.


    I'm a bad boy. I generally make things public unless an overwhelming
    reason not to. :^)


    > It seems a little yucky, but the yuckiness is localized to your exception
    > hierarchy, the code that uses it is clean.


    Yeah...yucky, but if it works and is maintainable then it's OK by me. I
    just had to see if someone could think of something more elegant before I
    go that route in the morning.

    thanks
     
    noone, Jan 23, 2007
    #4
  5. noone

    Greg Guest

    noone wrote:
    > On Mon, 22 Jan 2007 20:54:05 -0800, Michael wrote:
    >
    > > Here's how I've solved this in the past:
    > >
    > > 1) Create a virtual method 'output,' as you suggested virtual ostream&
    > > output(ostream& s) const;

    >
    > Yes. I was hoping to avoid this but you are confirming my suspicions
    >
    > > It seems a little yucky, but the yuckiness is localized to your exception
    > > hierarchy, the code that uses it is clean.

    >
    > Yeah...yucky, but if it works and is maintainable then it's OK by me. I
    > just had to see if someone could think of something more elegant before I
    > go that route in the morning.


    The best way to deal with an over-engineered solution is not to look
    for ways to under-engineer its integration into the program.
    Instead, I would recommend adopting a solution more in line with the
    scope of the problem that needs to be solved.

    Specifically - and I feel that I must square with you - there is no
    such thing as an "exception hierarchy." There is no literature that
    describes "exception hierarchies", there are no experts who study them
    for a living, no journals dedicated to their research - in short,
    nothing.

    Nor is there much value in thinking about exceptions as a "hierarchy"
    in the first place. In fact, few mental models could be any less
    accurate. In reality exceptions are nearly all identical - only the
    particulars of error itself vary. Therefore I think it would be more
    productive (and a lot less work) to replace the elaborate exception
    class hiearchy with a single exception type. And have this type simply
    store the exception's useful information - which could include:

    1. an exception id to uniquely identify the error (int)
    2. description as a string (for diagnostic messages)
    3. point at which exception was thrown (filename, line number)
    4. other exception-specific information

    After all, the goal of this work should be for the program make the
    best use out of C++ expections. The goal should not be how to take an
    elaborate class hiearachy that happens to be lying around, stick it
    into a program so that a) it will do something useful and b) won't
    require a lot of work to get to point a).

    Or to put it another way: the focus should never be on finishing the
    solution - the focus should always be on eliminating the problem.

    Greg
     
    Greg, Jan 23, 2007
    #5
  6. noone

    noone Guest

    On Mon, 22 Jan 2007 23:09:56 -0800, Greg wrote:

    > Specifically - and I feel that I must square with you - there is no such
    > thing as an "exception hierarchy." There is no literature that describes
    > "exception hierarchies", there are no experts who study them for a living,
    > no journals dedicated to their research - in short, nothing.


    > Nor is there much value in thinking about exceptions as a "hierarchy" in
    > the first place. In fact, few mental models could be any less accurate. In
    > reality exceptions are nearly all identical - only the particulars of
    > error itself vary. Therefore I think it would be more productive (and a
    > lot less work) to replace the elaborate exception class hiearchy with a
    > single exception type. And have this type simply store the exception's
    > useful information - which could include:
    >
    > 1. an exception id to uniquely identify the error (int) 2.
    > description as a string (for diagnostic messages) 3. point at which
    > exception was thrown (filename, line number) 4. other
    > exception-specific information
    >
    > After all, the goal of this work should be for the program make the best
    > use out of C++ expections. The goal should not be how to take an elaborate
    > class hiearachy that happens to be lying around, stick it into a program
    > so that a) it will do something useful and b) won't require a lot of work
    > to get to point a).



    Greg.

    I suggest getting a copy of "The C++ Programming Language" by the
    creator of the language Bjarne Stroustrup and reading the section on
    exceptions thoroughly before writing such things, especially given the
    authoritative tone that seems to come across in what is written above.

    The original post was to address the capabilities of virtuals vs friends.
    Exceptions just happened to be the real-world example case I chose to
    display the current and preferred behavior.

    Happy hacking!
    Rob
     
    noone, Jan 26, 2007
    #6
    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. John Cho
    Replies:
    1
    Views:
    301
    Jonathan Turkanis
    Mar 3, 2004
  2. csudha

    Reg virtual function and friend function

    csudha, Feb 20, 2005, in forum: C Programming
    Replies:
    5
    Views:
    314
    infobahn
    Feb 21, 2005
  3. Alan Johnson
    Replies:
    1
    Views:
    380
    red floyd
    Mar 24, 2007
  4. Replies:
    4
    Views:
    539
  5. Peter
    Replies:
    2
    Views:
    278
    Öö Tiib
    Jun 6, 2013
Loading...

Share This Page