Реализация оператора‹‹ для производного класса

Итак, у меня есть базовый класс (Shape) и три производных класса: Circle, Rectangle и Square (Square получен из Rectangle). Я пытаюсь реализовать оператор ‹‹, который просто вызывает правильную функцию отображения для того, что его вызвало. Однако я не думаю, что у меня правильный синтаксис. Вот фрагмент - где я ошибся?

class Shape
{
     public:
     Shape(double w = 0, double h = 0, double r = 0)
     {
          width = w;
          height = h;
          radius = r;
     }

     virtual double area() = 0;
     virtual void display() = 0;

     protected:
     double width;
     double height;
     double radius;
};

ostream & operator<<(ostream & out, const Shape & s)
{
      s.display(out);
      return out;
}

class Rectangle : public Shape
{
     public:
     Rectangle(double w, double h) : Shape(w, h)
     {
     }

     virtual double area() { return width * height; }
     virtual void display() 
     {
        cout << "Width of rectangle: " << width << endl;
        cout << "Height of rectangle: " << height << endl;
        cout << "Area of rectangle: " << this->area() << endl;
     }
};

person user2302335    schedule 11.05.2013    source источник
comment
Очевидно, что display() должен принимать в качестве параметра ostream & out и писать в out, а не в cout.   -  person Alexander Shukaev    schedule 11.05.2013


Ответы (3)


Вы звоните display следующим образом:

s.display( out );

Но display определяется как:

vritual void display() = 0;

Функция была объявлена ​​и определена без параметров. Он должен принимать ссылку на std::ostream в качестве параметра:

virtual void display(std::ostream &) = 0;

Это также должен быть метод const, поскольку вы передаете объект const через перегрузку operator <<:

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

Не забывайте, что в определении display вы должны записывать объект ostream, а не конкретно std::cout.

Вот программа для компиляции на Ideone.

person 0x499602D2    schedule 11.05.2013

У вас тут ряд проблем. Во-первых, давайте разберемся с проблемой печати:

ostream & operator<<(ostream & out, const Shape & s)

Здесь вы проходите const Shape. Это означает, что вы можете вызывать только const методы для s, которые вы передаете. Однако вы не отметили ни один из методов в базовом (или производном) классе как const. Ни area, ни display не должны изменять состояние объекта. Во-вторых, вы пытаетесь вызвать s.display(out), то есть передать ostream& в display. Сигнатура функции, которая у вас есть, не отражает этого. Итак, сложив все вместе, мы получаем:

 virtual double area() const = 0;
 virtual void display(ostream& out) const = 0;

У вас также есть некоторые другие проблемы - базовый класс, который не объявляет виртуальный деструктор. Если вы планируете использовать класс полиморфно, он должен иметь виртуальный деструктор:

virtual ~Shape() { }

Вам также необходимо изменить свои методы в производном классе:

 double area() const { return width * height; }

 void display(ostream& out) const
 {
    out << "Width of rectangle: " << width << endl;
    out << "Height of rectangle: " << height << endl;
    out << "Area of rectangle: " << area() << endl;
 }

Обратите внимание, что display в Rectangle всегда печаталось в cout заранее.

person Yuushi    schedule 11.05.2013

Вы почти правильно поняли, вот рабочее решение:

#include <iostream>

using std::cout;
using std::endl;
using std::ostream;

class Shape
{
     public:
     Shape(double w = 0, double h = 0, double r = 0)
     {
          width = w;
          height = h;
          radius = r;
     }

     virtual ~Shape() {} // Recommended!

     virtual double area() const = 0;
     virtual void display(ostream & out) const = 0;

     protected:
     double width;
     double height;
     double radius;
};

ostream & operator<<(ostream & out, const Shape & s)
{
      // Since `s` is `const`, then `display` method should be `const` too.
      s.display(out);
      return out;
}

class Rectangle : public Shape
{
     public:
     Rectangle(double w, double h) : Shape(w, h)
     {
     }

     virtual double area() const { return width * height; }
     virtual void display(ostream & out)  const
     {
        // Since `display` method is `const`, then `area` method should be
        // `const` too.
        out << "Width of rectangle: " << width << endl;
        out << "Height of rectangle: " << height << endl;
        out << "Area of rectangle: " << this->area() << endl;
     }
};


void main() {
    Rectangle r(1, 2);

    cout << r << endl;
}

Пожалуйста, обратите внимание на квалификаторы const, которые обеспечивают const-правильность методов класса. Я добавил несколько полезных комментариев, чтобы вы могли плавно следовать логике. Возьмите за правило: если метод не изменяет членов класса, вам следует объявить его const.

person Alexander Shukaev    schedule 11.05.2013