0

I wrote this simple program to practice overloading.

This is my code:

#include <iostream>
#include <string>
using namespace std;

class sex_t
{
    private:
        char __sex__;

    public:
        sex_t(char sex_v = 'M'):__sex__(sex_v)
        {
            if (sex_v != 'M' && sex_v != 'F')
            {
                cerr << "Sex type error!" << sex_v << endl;
                __sex__ = 'M';
            }
        }

        const ostream& operator << (const ostream& stream)
        {
            if (__sex__ == 'M')
                cout << "Male";
            else
                cout << "Female";
            return stream;
        }
};

int main(int argc, char *argv[])
{
    sex_t me('M');
    cout << me << endl;
    return 0;
}

When I compile it, it print lots of error messages:

The error message was in a mess.

It's too hard for me to found a useful message.

sex.cpp: 在函数‘int main(int, char**)’中:
sex.cpp:32:10: 错误: ‘operator<<’在‘std::cout << me’中没有匹配
sex.cpp:32:10: 附注: 备选是:
/usr/include/c++/4.6/ostream:110:7: 附注: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostre
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
thlgood
  • 1,275
  • 3
  • 18
  • 36
  • 2
    `cerr << "Sex type error!" << sex_v` You're right, I've never heard of that position. – chris Jun 27 '12 at 02:58
  • 1
    In all seriousness, one thing you should definitely NOT do is use two leading underscores. That is reserved for the implementation. – chris Jun 27 '12 at 03:00
  • what should I do? use `_sex_` OR other? – thlgood Jun 27 '12 at 03:02
  • Some common ones for class members are `m_sex`, `_sex`, `sex_`, or just `sex`, depending on what you name your function parameters. – chris Jun 27 '12 at 03:04
  • Say, don't you regret not naming the sole member variable `gender` instead of `sex`? – Sergey Kalinichenko Jun 27 '12 at 03:14
  • I think `m_chSex` or `m_chGender` is ok – shengy Jun 27 '12 at 03:18
  • 5
    Sex, streams, `friend`s accessing `private` members... Either I am just discovering unintentional innuendo or Stroustrup is a pervert. – Sage Gerard Jun 27 '12 at 03:21
  • @thlgood: SO's [C++ FAQ](http://stackoverflow.com/questions/tagged/c%2b%2b-faq) has [an answer for that](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – sbi Jun 27 '12 at 07:09

3 Answers3

4

The argument and return from operator<< are non-const. Also it needs to be a non-member- you have written an overload for me << cout, not cout << me. Also, identifiers leading with two underscores are reserved for the implementation and using them is Undefined Behaviour.

Puppy
  • 144,682
  • 38
  • 256
  • 465
3

"C++ Primer 4th Edition" Chapter 14 section 14.2 Input and Output Operators:

IO Operators Must Be Nonmember Functions, We cannot make the operator a member of our own class. If we did, then the left-hand operand would have to be an object of our class type:

// if operator<< is a member of Sales_item
     Sales_item item;
     item << cout;

The general skeleton of an overloaded output operator is

   // general skeleton of the overloaded output operator
     ostream&
     operator <<(ostream& os, const ClassType &object)
     {
         // any special logic to prepare object

         // actual output of members
         os << // ...

         // return ostream object
         return os;
     }

The first parameter is a reference to an ostream object on which the output will be generated. The ostream is nonconst because writing to the stream changes its state. The parameter is a reference because we cannot copy an ostream object.

The second parameter ordinarily should be a const reference to the class type we want to print. The parameter is a reference to avoid copying the argument. It can be const because (ordinarily) printing an object should not change it. By making the parameter a const reference, we can use a single definition to print const and nonconst objects.

The return type is an ostream reference. Its value is usually the ostream object against which the output operator is applied.

EDIT:

I tried to modify your code, and if you use __sex__ as sex_t's private member, you should write another get function to get the 'M' or 'F', and if you call it in your operator<< function, you will probably get an error, because a const reference could only call a const function, so you should make your get function a const function, just for reminde:)

shengy
  • 9,461
  • 4
  • 37
  • 61
  • Another advantage of using a *const* reference is that you can do something like this: `std::cout << sex_t('M');`, which cannot bind to a non-const reference. – chris Jun 27 '12 at 03:19
  • @chris Yes:) I nearly forgot that – shengy Jun 27 '12 at 03:21
1

When overloading for streams, you declare a << operator globally and/or as a friend (with benefits) to your class so it can access its 'private members' (ooh...). You can declare a friend inside the class to declare it globally. Do not use const on the streams.

Next, use the passed stream in your overload. In your method, you use cout when you would have used it anyway by just using the stream argument.

I have not tested this, but see if it works for you.

class sex_t
{
private:
    char __sex__;
public:
    sex_t(char sex_v = 'M'):__sex__(sex_v)
    {
        if (sex_v != 'M' && sex_v != 'F')
        {
            cerr << "Sex type error!" << sex_v << endl;
            __sex__ = 'M';
        }
    }

    friend ostream& operator << (ostream& stream, sex_t& sex);
};


ostream& operator << (ostream& stream, sex_t& sex)
{
    if (__sex__ == 'M')
        stream << "Male";
    else
        stream << "Female";
    return stream;
}
Sage Gerard
  • 1,311
  • 8
  • 29