Virtual functions work by calling the correct function through a pointer in something called the vtable. So, some offset from this
gives a pointer to the vtable, and some offset into the vtable gives the address of the function for that actual type of object.
However, this won't work (directly) with an overload of operator<<
for inserting an object into a stream. A virtual function must be a member function--but when you're overloading a member function, its left operand must be an object of the type for which you're providing an overload. That is, with an overloaded member function, a << b
is invoked as a.operator<<(b);
. For stream insertion that won't work, because the left operand is always the stream rather than the type you're going to insert into the stream.
To get around that, you do make the operator itself a friend (which is never a member).
To get virtual behavior, you have that invoke a virtual member function:
class base {
public:
virtual std::ostream &write(std::ostream &os) const {
// write myself to the passed stream
return os;
}
friend std::ostream &operator<<(std::ostream &os, base const &b) {
return b.write(os);
}
};
class derived : public base {
public:
std::ostream &write(std::ostream &os) const override {
// write myself to the passed stream
return os;
}
};
Now the overloaded operator gets called for the correct types. It, in turn, just invokes the correct virtual function for the object that was actually passed (base
, derived
, or some other derived class if you choose to create one).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…