Класс Point и Line в c ++? - PullRequest
       33

Класс Point и Line в c ++?

7 голосов
/ 19 февраля 2009

Я изучаю C ++ (и программирую в целом) и пытаюсь создать класс Point и класс Line.

Линия должна состоять из 2 точечных объектов.

Могут ли гуру C ++ просмотреть мою работу и сказать мне, если вы правильно используете указатели, ссылки и классы?

class Point
{
    private:
        int x, y;
    public:
        Point() : x(0), y(0) {}
        Point(int x, int y) : x(x), y(y) {}
}

class Line
{
    private:
        Point *p1;
        Point *p2;
    public:
        Line(Point &p1, Point &p2) : p1(p1), p2(p2) {}

        void setPoints(Point &p1, Point &p2)
        {
            this->p1 = p1;
            this->p2 = p2;
        }
}

Ответы [ 11 ]

7 голосов
/ 19 февраля 2009

Вы не должны вообще использовать указатели в своем коде. Используйте актуальные объекты. Указатели на самом деле используются довольно редко в C ++.

class Point
{
    private:
        int x, y;
    public:
        Point() : x(0), y(0) {}
        Point(int x, int y) : x(x), y(y) {}
}

class Line
{
    private:
        Point p1;
        Point p2;
    public:
        Line(const Point & p1, const Point & p2 ) : p1(p1), p2(p2) {}

        void setPoints( const Point & ap1, const Point & ap2)
        {
            p1 = ap1;
            p2 = ap2;
        }
}
5 голосов
/ 19 февраля 2009

Независимо от того, являются ли члены Point вашего линейного класса указателями или нет, создает совершенно другой тип класса. Использование указателей приведет к классическому подходу в стиле CoGo, который можно рассматривать как точки, похожие на гвозди на доске, а линии - как резиновые полосы, соединяющие эти гвозди. Изменение точки похоже на перемещение гвоздя, все связанные линии работают автоматически, что желательно в некоторых случаях.

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

Это критическое проектное решение для ваших классов на данном этапе.

Редактировать: Как отмечалось в других постах и ​​в комментарии ниже, использование простых указателей для достижения связи между несколькими линиями и точками также представляет серьезную потенциальную проблему. В частности, если точка удалена или перемещена в памяти, все указатели, относящиеся к этой точке, должны быть обновлены. На практике это, как правило, преодолевается путем использования уникальных идентификаторов точек для поиска точки, а не простых указателей. Это также позволяет легко сериализовать / сохранить структуры CoGo. Таким образом, наш класс точек будет иметь статический член для получения точки на основе идентификатора, а наш класс линии будет иметь два идентификатора точек, а не указатели.

5 голосов
/ 19 февраля 2009

+ 1, что сказал zabzonk.

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

  1. У вас есть несколько очков
  2. Вы хотите создать линии, используя эти точки
  3. Вы хотите изменить значения точек и неявно изменить линии.

Шаг 3, описанный выше, может быть достигнут, если линии содержат указатели на существующие точки. Хотя это создает сложность (например, «когда вы уничтожаете экземпляр Point, что происходит с экземплярами Line, которые содержат указатели на Point?»), Которых не существует, когда (как предположил zabzonk) каждая строка содержит свои собственные значения Point.

2 голосов
/ 19 февраля 2009

Нет необходимости использовать указатели в вашем классе Line.

Также неверна следующая строка:

Line(Point &p1, Point &p2) : p1(p1), p2(p2) {}

Почему? Вы присваиваете Point & (p1) для Point * (Line :: p1), что недопустимо. Вы бы хотели указатели там.

Ваш класс Point не имеет возможности изменять свои данные. Не слишком полезно ...

Класс Line для меня будет выглядеть примерно так:

class Line
{
    private:
        Point p1, p2;

    public:
        Line()
        {
        }

        Line(Point start, Point end) :
            p1(start), p2(end)
        {
        }

        const Point &startPoint() const
        {
            return p1;
        }

        Point &startPoint()
        {
            return p1;
        }

        const Point &endPoint() const
        {
            return p2;
        }

        Point &endPoint()
        {
            return p2;
        }
};

Теперь вы можете редактировать свою строку следующим образом:

Line line;
line.startPoint() = Point(4, 2);
line.endPoint() = Point(6, 9);
2 голосов
/ 19 февраля 2009

Я бы предпочел это ...

class Point
{
    private:
        int x, y;
    public:
        Point() : x(0), y(0) {}
        Point(int x, int y) : x(x), y(y) {}
}

class Line
{
    private:
        Point p1;
        Point p2;
    public:
        Line(const Point &p1, const Point &p2) : p1(p1), p2(p2) {}

        void setPoints(const Point &p1, const Point &p2)
        {
            this->p1 = p1;
            this->p2 = p2;
        }
}
1 голос
/ 19 февраля 2009

Я вижу небольшую ценность в создании указателей Point (кроме как для значения иронии). Ваша точка занимает 8 байт в 32-битной системе (2 целых). Указатель занимает 4 байта. вы экономите 4 байта.

Что касается корректности, ваш конструктор Line принимает ссылки, но вы назначаете их указателям. Это не должно даже компилироваться. Вы также делаете то же самое в setPoints. Было бы лучше просто сделать две точки фактическими объектами и скопировать их значения.

1 голос
/ 19 февраля 2009

Я заметил пару вещей:

  • Вы можете объединить оба ваших точечных конструктора в один конструктор со значениями по умолчанию.
  • Ваше использование указателей совершенно не нужно. Используйте сам объект.
  • Вы используете и указатели и ссылки взаимозаменяемо. Не перепутайте их и не смотрите последний пункт.
0 голосов
/ 19 февраля 2009

Используйте объекты Point в вашем классе Line. Владение точками неясно, и вы рискуете получить висячие указатели или утечку памяти.

Ваш конструктор по умолчанию является проблемой, так как вы редко захотите создать точку в точке (0,0). Вам лучше установить значения по умолчанию x, y на что-то вроде MAXINT и утверждать, что любое использование Point не имеет MAXINT в качестве одного из своих значений. Иметь функцию is_valid (), чтобы клиенты могли тестировать. Ваш класс Line также может иметь предварительное условие, что его две точки не являются недействительными. Выгода от того, что допустимая точка не имеет значения MAXINT, заключается в том, что вы можете определить, когда точки не были должным образом инициализированы, и вы сможете устранить некоторые иные трудные для обнаружения ошибки в использовании класса.

0 голосов
/ 19 февраля 2009

Прежде чем спросить о мнении языкового гуру, начните думать о дизайне, в данном случае особенно о времени жизни ваших объектов: должна ли точка существовать без линии? Линии разделяют точки? Кто создает точку, когда она перестает существовать? Являются ли две точки с одинаковыми координатами одинаковыми или просто равными (одна может быть красной, другая - синей)? ...

Похоже, что большинство здесь согласны с тем, что вам следует использовать семантику значений в такой небольшой базе кода. Иногда проблема требует, чтобы многие стороны ссылались на один и тот же объект (то есть на точку), а затем использовали указатели (или ссылки).

Выбор между указателем и ссылкой все еще остается другим. Я предпочитаю использовать ссылку при реализации агрегации (строка не может существовать без конечных точек) и указатель при реализации менее «интимного» отношения.

0 голосов
/ 19 февраля 2009

Компилятор выдаст ошибки по этому коду:

  1. В списке инициализации конструктора Line вы присваиваете ссылку Point на p1 члену класса p1, который является указателем на Point. Чтобы получить это для компиляции, вы должны использовать Line (Point & p1, Point & p2): p1 (& p1), p2 (& p2).
  2. Та же проблема возникает в методе заданных значений. Это должно быть изменено на это-> p1 = & p1 и т. Д.
  3. Незначительная проблема: после закрытия}, поставьте точку с запятой (;)

Я думаю, что это завершает синтаксис.

Есть еще одна проблема с кодом:

Члены класса p1 и p2 в Line являются указателями на экземпляры Point. Кто создает эти экземпляры и кто будет удалять их, когда они больше не нужны? Если вы создаете свой класс таким, какой он есть сейчас, код, который создает экземпляр Line, передает два экземпляра Point в конструктор. Если эти экземпляры Point удаляются до того, как будет создана линия, в строке останутся два висячих указателя (указатели, которые больше не ссылаются на действительный экземпляр).

Кроме того, два экземпляра Point, которые теперь являются частью Line, могут быть изменены из кода вне класса Line. Это может привести к очень нежелательным ситуациям.

В этой ситуации я бы объявил члены p1 и p2 как Point (вместо указателя на Point). Таким образом, экземпляры Point, которые передаются в конструктор, копируются в члены класса. Пока Линия существует, члены Point будут существовать. Они могут быть изменены только самим классом строки.

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