Проблема с конструктором C ++ - PullRequest
37 голосов
/ 11 мая 2011

РЕДАКТИРОВАТЬ: Этот вопрос возник, и я думаю, что я его исправил!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.Когда я удаляю это, он говорит мне, что «не может создать экземпляр абстрактного класса».Что это значит?

РЕДАКТИРОВАТЬ: Вот главное:

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

Ответы [ 10 ]

23 голосов
/ 11 мая 2011

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

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

}

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

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

10 голосов
/ 11 мая 2011

Если речь идет о лучших практиках C ++, то:

  1. Передать строковые параметры по константной ссылке;
  2. Используйте список инициализаторов и инициализируйте цвет, передав его родительскому конструктору, а не setColour.
9 голосов
/ 11 мая 2011

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

7 голосов
/ 11 мая 2011

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

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.

6 голосов
/ 11 мая 2011

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

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

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

3 голосов
/ 11 мая 2011

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

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

2 голосов
/ 14 мая 2011

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

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

  2. Вызовите конструктор базового класса , чтобы установить цвет.

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

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

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

  6. printDetails, вероятно, должно быть virtual , так что вы можете вызвать его с указателем базового класса. Текущая реализация может работать не так, как задумано.

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

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

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

2 голосов
/ 11 мая 2011

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

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

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

1 голос
/ 11 мая 2011

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

0 голосов
/ 01 июня 2011

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...