Подтвердить что ты не робот

Проблема с конструктором С++

РЕДАКТИРОВАТЬ: Этот вопрос возник, и я думаю, что я его запустил! Go StackOverflow!!: D

У меня есть экзамены, и один из вопросов на экзаменах в прошлом году состоял в том, чтобы выявить проблему с реализацией следующего конструктора и написать исправленную.

Rectangle::Rectangle(string col, int len, int br)
{
    setColour(col);
    length =len;
    breadth=br;
}

Определения классов следующие:

class Polygon
{
public:
    Polygon(string col="red");
    void printDetails(); // prints colour only
    virtual double getArea()=0;
    void setColour(string col);
private:
    string colour;
};


class Rectangle : public Polygon
{
public:
    Rectangle(string, int, int);
    void printDetails(); // prints colour and area
    // for part 3, delete the line below
    double getArea();
private:
    int length;
    int breadth;
};

Я написал код в компилятор, и он работает нормально. Я предполагаю, что вопрос связан с наследованием, поскольку string colour; является закрытым, но setColour является общедоступным, поэтому я не могу понять его. Если нет Rectangle::Rectangle(string col, int len, int br):length(len), breadth(br), а затем установите цвет внутри конструктора или что-то в этом роде.

Единственное, что стоит 3 знака, так это не такая большая сделка, если никто не хочет отвечать, но я думаю, что если у меня будет карьера программиста, то в моих интересах знать как можно больше.;)

Спасибо за любую помощь.

PS, см. getArea() в Rectangle. Когда я удаляю это, он говорит мне, что "не может создать экземпляр абстрактного класса". Что это значит?

EDIT: Здесь главное:

void main (void)
{
    Rectangle rect1 ("blue",5,6);
    Rectangle *prect2 = new Rectangle("red",5,6);
    rect1.setColour("red");
    rect1.printDetails();
    prect2->printDetails();
}
4b9b3361

Ответ 1

Я не вижу ничего плохого, хотя вы могли бы сделать его более эффективным, используя список инициализации (в противном случае ваши частные члены обоих классов инициализируются дважды):

Rectangle::Rectangle(string col, int len, int br) 
: Polygon(col), length(len), breadth(br)
{

}

Обратите внимание, что список инициализации может также вызвать конструктор Polygon.

См. Почему я должен использовать список инициализации членов? для полного описания преимуществ использования списков инициализации.

Ответ 2

Если это о лучших практиках С++, то:

  • передать строковые параметры с помощью ссылки const;
  • Используйте список инициализаторов и инициализируйте цвет, передав его родительскому конструктору, а не setColour.

Ответ 3

Единственное, что я вижу с летучей мыши, - это два printDetails(), но базовый класс один не является виртуальным, поэтому вы не получите ожидаемого полиморфного поведения.

Ответ 4

Основной "вопрос", который я вижу (и это немного второстепенный), заключается в том, что производный конструктор позволяет родительскому классу использовать значение по умолчанию colo (u) r ( "красный" ), а затем поставляет свои собственные. Это своего рода расточительство, когда вы могли бы дать ему правильное решение с самого начала.

Rectangle::Rectangle(string col, int len, int br) : Polygon(col) {
    length =len;
    breadth=br;
};

Теперь, выполнив вышеизложенное, вы могли бы так же инициализировать всех участников:

Rectangle::Rectangle(string col, int len, int br) 
    : Polygon(col), length(len), breadth(br) {};

Хммм. Теперь, когда я смотрю на это, там что-то не так. Ваши конструкторы передают объекты std::string копией и не изменяют их. Это тоже отходы. Все параметры конструктора string должны быть изменены на string const &. Это потенциально позволяет избежать создания дополнительной копии строки во время выполнения и уведомляет компилятор и пользователей о том, что вы на самом деле не изменяете входные строки (что является хорошей практикой, когда вы на самом деле не являетесь).

Итак, окончательная версия будет больше похожа:

Rectangle::Rectangle(string const & col, int len, int br) 
    : Polygon(col), length(len), breadth(br) {};

Эта формулировка выводит вас из 4 std::string конструкций (и 3 разрушений) для каждого конструктора Rectangle, который называется до 2. Он может быть снесен до единицы путем внесения такого же изменения в конструктор Polygon.

Ответ 5

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

Rectangle::Rectangle(string col, int len, int br) : Polygon(col)
{
    //setColour(col);
    length =len;
    breadth=br;
}

Относительно getArea():
Причина, по которой он не компилируется, когда вы его удаляете, заключается в том, что эта функция отмечена как чистый виртуальный в вашем классе Polygon virtual double getArea()=0; с помощью =0;

Ответ 6

Для вашего PS относительно Rectangle::getArea(): объявление в многоугольнике virtual double getArea()=0; означает, что функция является чистой виртуальной функцией. Вы можете думать об этом концептуально: "У всех полигонов есть область, поэтому я должен иметь возможность спросить, что это такое, но если у полигона нет определенного типа (квадрат, круг), он не будет знать, в чем его область".

Это означает, что ваш класс Polygon является абстрактным классом. Не определяя getArea() в классе Rectangle, ваш класс прямоугольников также является абстрактным классом. Вы не можете создать экземпляр Rectangle, потому что компилятор не знает об определении функции Rectangle::getArea().

Ответ 7

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

Rectangle::Rectangle(string col, int len, int br)
    : Polygon(col), length(len), breadth(br)

Это использует конструктор базового класса, так что он немного опрятен.

Ответ 8

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

  • Используйте списки инициализаторов для назначения значений.

  • Вызов конструктора базового класса для установки цвета.

  • Строка не может быть лучшим типом для представления цвета. Возможно, здесь будет лучше перечисление или отдельный класс цветов. Это также предотвращает передачу недопустимых цветов, если это правильно сделано.

  • Говоря о недопустимых значениях: длина и ширина должны быть проверены в конструкторе (вы не хотите, чтобы в итоге были отрицательные области, не так ли?). По крайней мере, используйте утверждение. Это не влияет на сборку релизов, но предотвращает ошибки разработки. Для более открытого интерфейса исключения могут также быть вариантом (это в какой-то мере личный вкус).

  • Если вы действительно хотите использовать строку для цвета, передайте ее по ссылке const (и, вероятно, проверьте для случаев краев, таких как пустая строка).

  • printDetails должен быть виртуальным, поэтому вы можете вызвать его с помощью указателя базового класса. Текущая реализация может не соответствовать требованиям.

  • Класс, похоже, предназначен для полиморфизма. Необходимо определить виртуальный деструктор, если требуется удаление из указателя базового класса. Поскольку уже существует виртуальный метод, он, вероятно, тоже не повредит.

  • getArea и printDetails должны быть объявлены как const, так что их можно вызвать в объектах const. Они не должны изменять объект.

Это всего лишь список возможностей. Многие из них зависят от предполагаемого использования класса и могут не понадобиться, но не мешает их тщательно рассмотреть.

Ответ 9

Как упоминалось, printDetails не будет вести себя так, как ожидалось.
Я также думаю, что просто объявление getArea() в классе Rectangle является изменчивым, потому что вы не предоставляете ему реализацию, и если вы случайно назовете его внутри кода, вы получите ошибку компоновщика.

Ответ 10

Возможна проблема с порядком инициализации. Polygon:: setColour может вызвать чистый виртуальный Polygon:: getArea. (Нет никаких указаний на то, что это необходимо, но такая возможность существует.) Реализация в Rectangle, по-видимому, должна была бы иметь длину и ширину для вычисления области, но они еще не инициализированы.

Минимальное исправление - инициализировать длину и ширину перед вызовом setColour:

Rectangle::Rectangle(string col, int len, int br)
{
    length =len;
    breadth=br;
    setColour(col);
}

Было бы лучше, конечно, отказаться от объявления pure virtual getArea() от Polygon, потому что это не похоже на какие-либо методы Polygon. Но это выходит за рамки вопроса.