Можно ли сделать виртуальным оператор >>?

Можно ли в абстрактном базовом классе сделать виртуальным оператор вывода <<, чтобы в дальнейшем переопределить его в наследниках? Пока что сделал так. Базовый класс:

class Pair
{
private:
    long int first;
    int second;
public:
    friend virtual std::ostream& operator << (std::ostream& out_str, Pair& to_out) = 0;
};

Наследник:

class Money: public Pair
{
public:
    friend std::ostream& operator << (std::ostream& out_str, Pair& to_out) override;

Компилятор ругается на override, считает что нужна точка с запятой.


Ответы (3 шт):

Автор решения: user7860670

Оператор <<, как и любой другой нестатический метод класса, можно сделать виртульным. Однако такая форма оператора << принимает экземпляр класса в качестве неявного первого аргумента:

class base
{
    public: virtual base &
    operator <<(int x) = 0;
};

class derived: public base
{
    public: base &
    operator <<(int x) override
    {
        return *this;
    }
};

https://godbolt.org/z/m-FVzt

А запись вида std::ostream& operator << (std::ostream& out_str, Pair& to_out) служит для объявления свободной функции двух аргументов.

→ Ссылка
Автор решения: HolyBlackCat

Напрямую нельзя, потому что friend создает обычную функцию, а не метод.

Нужно вынести содержимое operator<< в метод, который потом переопределять:

virtual void Print(std::ostream &out_str) const = 0;

friend std::ostream &operator<<(std::ostream &out_str, Pair &to_out)
{
    to_out.Print(out_str);
    return out_str;
}
→ Ссылка
Автор решения: AR Hovsepyan

Можете делать, например, так:

class Pair
{
protected:
    long int first;
    int second;

    virtual std::ostream& put(std::ostream& os) const
    {
        os << first << ' ' << second;
        return os;
    }
public:
    Pair(long int a = 0, int b = 0) : first(a), second(b) {}
    friend  std::ostream& operator << (std::ostream& out_str, const Pair& to_out)
    {
        return to_out.put(out_str);
    }
};
class Money : public Pair
{
public:
    Money(const int a, const int b) : Pair(a, b) {}
protected:
   
    virtual std::ostream& put(std::ostream& os) const override
    {
        os << first << "  dollar,  " << second << "  cent\n";
        return os;
    }
};

То есть для всех Pair и его производных оператор просто вызывает виртуальную функцию, которая переопределена где нужно.

int main()
{    
    Pair p(2, 4);
    Money m(23, 34);
    cout << m << p;   
    return 0;
}
→ Ссылка