1

In my code, Manager is derived from Employee and each of them have an operator<< override.

class Employee{
protected:
    int salary;
    int rank;
public:
    int getSalary()const{return salary;}
    int getRank()const{return rank;}
    Employee(int s, int r):salary(s), rank(r){};
};
ostream& operator<< (ostream& out, Employee& e){
    out << "Salary: " << e.getSalary() << " Rank: " << e.getRank() << endl;
    return out;
}

class Manager: public Employee{
public:
    Manager(int s, int r): Employee(s, r){};
};
ostream& operator<< (ostream& out, Manager& m){   
    out << "Manager: ";
    cout << (Employee)m << endl;  //can not compile, how to call function of Employee?
    return out;
}

I hoped cout << (Employee)m << endl; would call ostream& operator<< (ostream& out, Employee& e), but it failed.

Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
ivory
  • 243
  • 4
  • 16
  • 3
    what is the compile error? – pippin1289 Oct 31 '13 at 15:34
  • 2
    You are slicing (at least the code is trying to; look it up). You need to write `static_cast(m)` instead of `(Employee)m`. – Simple Oct 31 '13 at 15:35
  • 2
    @ScarletAmaranth it should fail to compile because a temporary `Employee` can't bind to `Employee&`. If you are using MSVC then it has an incredibly stupid extension that allows this dangerous behaviour. – Simple Oct 31 '13 at 15:37
  • 2
    `(Employee)m` will result in a copy of the Employee part of m which is a temporary. I don't think it can match `Employee & e` parameter of your overload. – François Moisan Oct 31 '13 at 15:38
  • @Simple: Luckily g++ punishes you hard for that. :) – thokra Oct 31 '13 at 15:39

6 Answers6

8

Cast to a reference instead of a copy:

cout << (Employee&)m << endl;  //can not compile, how to call function of Employee?

Also note the ostream operator is in no way member of the class(it seems you are confused about that from the title of the question).

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
4

The usual way of doing this is to have (a possibly private or protected) virtual print (or any other suitable name) function in the base class that derived classes can override.

You only provide general operator<< for a reference to the base class and call print inside it. The overriding print functions can call the base's print, if need be.

jrok
  • 54,456
  • 9
  • 109
  • 141
  • His `operator<<` are actually external to the classes entirely. – Zac Howland Oct 31 '13 at 15:42
  • 1
    @ZacHowland I don't see a problem with that. You can declare them `friend`, as usual for stream operators. – jrok Oct 31 '13 at 15:42
  • @jrok. Sorry. I just don't think this is an answer to the actual OP's problem. Even though what you said is correct. – François Moisan Oct 31 '13 at 15:46
  • 1
    I didn't downvote, but it seems a shame to introduce polymorphism when the problem is solvable with static types. – Mike Seymour Oct 31 '13 at 15:47
  • @jrok I wasn't stating it as a problem, just as a note (the first sentence of your second paragraph kind of implies it as a class member - which it can be, but is not in this particular case). – Zac Howland Oct 31 '13 at 15:47
  • @MikeSeymour Ironically, it actually appears that he has the static type solution already (unless I'm misreading the purpose of the `rank` member) ... but even if I am, a simple boolean value in the `Employee` class solves that as well. – Zac Howland Oct 31 '13 at 15:51
  • @ZacHowland I see, I reworded it a little. – jrok Oct 31 '13 at 15:52
4

Change cout << (Employee)m << endl; to cout << (Employee&)m << endl;.

The explanation of the error message is this:

When you attempt the cast (Employee)m, you are creating a temporary. The operator<< overload takes a reference. You cannot take a reference to a temporary.

Since you really just want it to print it's own data (not make a copy of itself), you cast the reference you have to the reference of the type you need (it's base class).

As jrok pointed out in his answer, you can also accomplish this by providing a virtual function to print the data. That would be a simpler approach as it would not require you to overload operator<< for every derived class.

Community
  • 1
  • 1
Zac Howland
  • 15,777
  • 1
  • 26
  • 42
1

Your overload:

ostream& operator<< (ostream& out, Employee& e)

only works for references to Employee objects, so it won't work on non-reference values (like the result of a cast).

Normally, the prototype would be:

ostream& operator<< (ostream& out, const Employee& e)

which also provides the reassurance that printing an Employee doesn't mutate it. If you change that, things should work just fine. (ostream& does have to be a reference, not a const reference, because the ostream is mutated by the print operation.)

rici
  • 234,347
  • 28
  • 237
  • 341
0

There are two problems which combined make your compilation to fail.

(1) This declaration and definition:

    ostream& operator<< (ostream& out, Employee& e){
        out << "Salary: " << e.getSalary() << " Rank: " << e.getRank() << endl;
        return out;
    }

Despite you don't change e, you take it reference to non-const. This forbids you calling this operator on an rvalue.

(2) This line

cout << (Employee)m << endl;

As said by others you are slicing m. In addition, the cast (Employee) m returns a temporary Employee which is an rvalue.

In summary, the cast (Employee)m yields an rvalue which cannot bind to e.

You can fix either one or the other to make your code compiler but it's better to fix both problems to make your code more robust:

// ...
ostream& operator<< (ostream& out, const Employee& e) {
// ...

// ...
cout << static_cast<Employee&>(m) << endl;
// ...
Cassio Neri
  • 19,583
  • 7
  • 46
  • 68
0

First, you overload a global function. This is another concept than overriding. see Override and overload in C++

Next, your cast is wrong. This should do:

ostream& operator<< (ostream& out, Manager& m){   
    out << "Manager: ";
    cout << static_cast<Employee&>(m) << endl;  //can not compile, [...]?
   return out;
}

...if you really want to overload the global << operator.

Community
  • 1
  • 1
Wolf
  • 9,679
  • 7
  • 62
  • 108