Java-программист - как люди на C ++ используют классы? Указатели на классы, параметры по умолчанию? - PullRequest
7 голосов
/ 19 февраля 2009

Я знаю свой подход к объектно-ориентированному программированию, но я привык к Java, и я никогда не трогал C ++ до недавнего времени.

Я думаю, что моя проблема не столько связана с синтаксисом, сколько с философией ООП в С ++. Я понимаю разницу между указателями и адресами и стек, куча и прочее, но я все еще чувствую, что что-то упустил.

Вот пример: у меня есть класс (Shape), который содержит некоторые данные. у меня есть другой класс (приложение), используя несколько форм.

class Square {
    private: 
        int x;
        int y;
        int size;

    public:
        /* constructor */
        Square(int x, int y, int size);
}


class App {
    private:
        Square redSquare;
        Square blueSquare;

    public:
        void setup();
        void draw();
}

В какой-то момент что-то собирается создать экземпляр моего приложения и вызвать setup (). Проблема в том, что когда я объявляю класс App (скажем, в App.hpp), создаются экземпляры «redSquare» и «blueSquare», а не просто объявляются. Будучи программистом на Java, я бы в этом примере создал свои классы в setup (). Но это значит, что я не могу сделать это, как указано выше, мне нужно настроить redSquare и blueSquare как POINTERS, а затем я могу создать их, используя new в setup ().

Но так ли это? Или вы бы сделали конструктор по умолчанию параметры, создайте redSquare и blueSquare, как указано выше, а затем установите значения этих квадратов в App.setup (), используя что-то вроде Square.init (x, y, размер) или что-то? Или как-то иначе?

Вы когда-нибудь объединяли классы или только указатели?

Я, конечно, могу взломать это так или иначе, так что оно работает само, но у меня есть ощущение, что я делаю вещи "по-Java" и не понимаю, как думают программисты на C ++.

Ответы [ 12 ]

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

Мне кажется, что проблема связана с наличием метода "setup ()". IIUC, цель состоит в том, чтобы использовать приложение как:

App a;
a.setup();

В каком состоянии находится «а» перед вызовом установки ()? Что должно произойти, если на него вызывается draw ()? Если ответ примерно такой: «setup () должен быть вызван до того, как что-либо полезное может быть сделано с объектом App», то это означает, что setup () является «настоящим» конструктором App, и текущий ctor этого приложения не имеет смысла. Вывод: удалите метод "setup ()" и замените его значимым ctor.

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

Дайте приложению конструктор:

App :: App() 
    : redSquare( 10, 20, 100 ), blueSquare( 50, 500, 25 ) {
}
2 голосов
/ 19 февраля 2009

Во-первых, вам нужно выбрать, как должен вести себя ваш класс приложения, если draw () вызывается до setup ():

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

  2. Если вы не хотите, чтобы это когда-либо происходило, используйте указатели и защититесь от этого.

Некоторые заметки на 2:

  • У вас нет сборщика мусора в C / C ++, вам нужно «удалить» то, что вы «новый»
  • Вы можете использовать «умные указатели», чтобы иметь RAII (распределение ресурсов - инициализация), что упростит управление памятью
  • Возможно, вам следует использовать Null Design Pattern , чтобы избежать множества блоков if (redSquare == NULL).
  • В любом случае инициализируйте указатели в списке инициализации приложения либо NULL, либо нулевым квадратным объектом.
2 голосов
/ 19 февраля 2009

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

App(int bx, int by, bsize, int rx, int ry, int rsize) : 
blueSquare(bx, by, bsize), redSquare(rx, ry, rsize) {}

Это всего лишь пример, вы, вероятно, будете использовать лучший дизайн IRL.

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

Почему вы используете функцию настройки / инициализации? Вместо этого используйте конструктор, инициализирующие объекты - это конструктор raison d'être . Объекты, которые могут существовать в непригодных для использования состояниях, являются PItA, они требуют, чтобы каждая функция проверяла, можем ли мы что-то сделать с ними хорошо. Укрепляйте их инварианты и запрещайте их существование, пока вы не сможете полностью построить их.

Даже в Java функции init / setup кажутся мне сомнительной практикой.

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

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

Использование указателей приведет к тому, что ваш класс будет вести себя аналогично Java (это заставит вас явно создать экземпляр класса или метода «setup»). В Java каждый объект является ссылкой (похожей (но не равной) на указатель), и нет эквивалента тому, что вы делаете с C ++, используя:

class A {
   B b;
}

Надеюсь, это поможет.

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

Я бы использовал Square * вместо Square в качестве частных членов App. Таким образом, сохраняется память, создание объектов Square в App может быть отложено до необходимости, либо они могут быть выполнены в конструкторах App, по умолчанию или иным образом. Разумеется, деструктор должен уничтожить два квадратных объекта, если они были созданы.

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

Класс Square имеет конструктор, который принимает 3 аргумента. Класс App не определяет конструктор - это означает, что компилятор предоставит конструктор по умолчанию (конструктор, который не принимает никаких параметров). В конструкторе класса по умолчанию все переменные-члены инициализируются конструктором по умолчанию. Так как ваш класс Square не имеет конструктора по умолчанию, ваш код не будет компилироваться.

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

class Square {
    private: 
        int x;
        int y;
        int size;

    public:
        /* constructor */
        Square(int x, int y, int size);

        int getX() const {return x;}
        int getY() const {return y;}
        int getSize() const {return size;}

        void setX(int nx) {x = nx;}
        void setY(int ny) {y = ny;}
        void setSize(int s) {size = s;}
}

Затем вызовите эти функции, чтобы изменить внутренние переменные Square.

0 голосов
/ 03 марта 2009

НЕТ C ++ этого способа.

C ++ путь:

Делай, что хочешь, я дам тебе столько веревки, сколько ты захочешь.
Черт возьми! ты можешь даже повеситься с ним, я не остановлю тебя!

Вы можете использовать указатели, но вы должны знать об утечках памяти! Вы должны определить, кто (как и в каком классе / объекте) владеет этим объектом, кто имеет исключительное право на его удаление!

ИЛИ, вы можете подключить сборщик мусора (я слышал, что есть некоторые популярные, но сам никогда не пробовал), а затем работать с указателями, как если бы вы были в Java.

0 голосов
/ 03 марта 2009

Если ваша setup () действительно не имеет параметров и не возвращает никаких значений, поместите эту функциональность в конструктор ( Полагаю, вы просто оставили их для краткости ).

Наличие функции setup () , которая должна вызываться после того, как ваш конструктор не является best , но может быть совершенно допустимым, если исключение в конструкторе не является вариантом. Ваша функция setup () может более гибко решать проблемы.

ОДНАКО: не позволяйте конструктору покинуть объект в состоянии, которое позже вызовет проблемы, а именно:

  • Инициализировать все указатели переменные-члены !! В общем, вы должны установить все на некоторые значимые значения по умолчанию. В абсолютном минимуме есть защитный бит, чтобы определить, была ли setup () выполнена, и обработать каждый случай, когда он может вас укусить.
  • В каждой функции, для которой необходимо вызвать setup () , убедитесь, что она есть, или затем вызовите ее.
  • И, конечно же, освободить все выделения в деструкторе!

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

Да, и не тратьте много времени, пытаясь избежать указателей в C ++, но обязательно научитесь избегать ловушек.

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