Thread: inheritance and operator<<

  1. #1
    Registered User
    Join Date
    Jul 2007
    Posts
    32

    inheritance and operator<<

    Hello,
    I've got this problem; probabily about inheritance:

    Code:
    class Fruit { }
    class DriedFruit : public Fruit { }
    class Walnut : public DriedFruit {
    	float _kCalories;
    public:
    	Walnut (float cal = 0) : _kCalories(0) { }
    	~Walnut() { }
    	friend std::ostream& operator<<(std::ostream& os, Walnut& w) {
    		return os << "provence = " << "\t" <<  "protein = " << w._kCalories<< endl;
    	}
    };
    //main.cpp
    	Fruit* f = new Walnut;	
    	cout << *f;
    
    //error
    error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Fruit' (or there is no acceptable conversion)
    //and many others....
    Any hints, please?

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's worth noting that
    friend std::ostream& operator<<(std::ostream& os, Walnut& w) {
    Should be const and take a const reference:
    friend std::ostream& operator<<(std::ostream& os, const Walnut& w) const {
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    There is no operator<< for Fruit, so you can't print *f (which is a Fruit, not a Walnut).

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Make a virtual print function in Fruit. Override it in derived classes as necessary to print the object. Make an operator<< just for the Fruit class that simply calls the print function. When you use operator<< on any Fruit or derived-from-Fruit object, it will call the Fruit overload of operator<< which will call the correct derived class' version of print.


    >> There is no operator<< for Fruit, so you can't print *f (which is a Fruit, not a Walnut).

    Actually, *f is a Walnut. However, when looking at what functions can be called, the compiler only can see the Fruit interface (because f is a pointer to a Fruit). Since the operator<< is not part of the Fruit interface, the compiler can't call it despite the fact that you as the programmer know that at runtime *f really is a Walnut.
    Last edited by Daved; 06-09-2008 at 03:17 PM.

  5. #5
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Daved View Post
    Actually, *f is a Walnut. However, when looking at what functions can be called, the compiler only can see the Fruit interface (because f is a pointer to a Fruit). Since the operator<< is not part of the Fruit interface, the compiler can't call it despite the fact that you as the programmer know that at runtime *f really is a Walnut.
    Can we say that syntactically *f is a Fruit, even if we know semantically that *f is a Walnut? The compiler can only access f through the Fruit interface, and it will even report with typeid that *f is a Fruit, not a Walnut.

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    I guess. I don't know what the proper terms are. The run-time or dynamic type of *f is Walnut. The compile-time or static type is Fruit.

    I know what you mean when you say that *f is a Fruit, I just want to make it clear that it is also a Walnut, just not from the compiler's viewpoint at the time it is trying to find the proper overload for operator<<.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    At compile time, the type is Fruit, not Walnut, since it isn't static polymorphism.
    (Runtime) Polymorphism works the other way around - a base class can encompass a type from any of its derived classes. But not the other way around, because a Fruit is not a Walnut.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by mickey0
    Any hints, please?
    Daved has given the hint, but also note that you should declare Fruit's destructor to be virtual, and Walnut can do with the compiler provided destructor.

    Quote Originally Posted by Elysia
    It's worth noting that
    friend std::ostream& operator<<(std::ostream& os, Walnut& w) {
    Should be const and take a const reference:
    friend std::ostream& operator<<(std::ostream& os, const Walnut& w) const {
    Actually, since it is a friend, it cannot be const, though it should take the Walnut by const reference. Of course, the print member function should be const.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    I suggest you make a function (inline) 'get_kCalories()', and then make the operator<< a free function:
    Code:
    std::ostream& operator<<(std::ostream& os, Walnut const& w) 
    {
        return os << "provence = " << "\t" <<  "protein = " << w.get_kCalories()<< endl;
    }

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Inline doesn't really matter nowadays, however, unless the function is in a header.
    The compiler will inline it for you if it deems it suitable. And a one-line function is almost always inlined.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    Even without the keyword 'inline'?

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes.
    The inline keyword is a suggestion to compilers to inline something, but they will typically do it anyway if they feel it a good optimization and will generally ignore the keyword if the compiler finds it a ridiculous suggestion.
    Last edited by Elysia; 06-10-2008 at 01:22 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    May 2008
    Location
    Paris
    Posts
    248
    Apparently the standard (2003 version, is there a newer one?) defines a difference in linking (external or internal).

    7.1.2 Function specifiers:

    A function declaration (8.3.5, 9.3, 11.4) with an inline specifier declares an inline function. The inline
    specifier indicates to the implementation that inline substitution of the function body at the point of call is
    to be preferred to the usual function call mechanism. An implementation is not required to perform this
    inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for
    inline functions defined by 7.1.2 shall still be respected.

    A function which has been defined in a .cpp file, so outside the class declaration, is inlined automatically even without the keyword 'inline'?

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I don't think the inline keyword will help if the function is in another source file, because the compiler, as I see it, must remember the "inline suggestion" at to which point it encounters the implementation. If the implementation is not within the current source file, then the compiler cannot determine if the function is suitable for inlining or not since it cannot see it, so I don't think inline will have an effect there (the compiler will disregard it).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    The inline keyword matters.

    A compiler will generally not inline a function that is not included in the compilation unit. As such, if you think that a function is a candidate for inlining, you should put it in a header file and use the inline key word. The use of the key word makes it possible to have multiple files include the definition without multiple definition errors.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. operator<< overload problem
    By stewie griffin in forum C++ Programming
    Replies: 5
    Last Post: 03-10-2009, 06:29 PM
  2. define operator<< for std::pair<string, int>
    By patiobarbecue in forum C++ Programming
    Replies: 2
    Last Post: 02-07-2009, 08:29 AM
  3. ostream operator<< () overload problems
    By jaybny in forum C++ Programming
    Replies: 2
    Last Post: 06-24-2006, 11:00 PM
  4. no match for 'operator<<' in.... Compile Problem!
    By njd in forum C++ Programming
    Replies: 5
    Last Post: 01-09-2006, 12:40 PM