2013-07-15 1 views
1

В C++ я часто (почти всегда) сталкивается с проблемами с конструкторами; Я никогда не знаю, как использовать параметры, и в итоге я в конечном итоге использую только конструктор без параметров для каждого класса. Затем я буду использовать сеттеры после каждого определения экземпляра. Например:Правило большого пальца для перегрузок конструктора C++?

// Obviously better 
Point p(5, 3); 

// ...and yet I end up using this 
Point p; 
p.setX(5); 
p.setY(3); 

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

// implements position and pixmap (image shown when painted) 
class Block : QObject { 
    public: 
     Block(const QPixmap &img = Pixmap(), QObject *parent = 0); 
     Block(const QPoint &pos, const QPixmap &img = Pixmap(), QObject *parent = 0); 
     Block(int x, int y, const QPixmap &img = Pixmap(), QObject *parent = 0); 
     Block(const Block &other); 
}; 

Имея только один класс с только два атрибутов (position и image), я уже получить четыре конструктора принимая четыре параметра в большинстве. Кроме того, я часто вижу, что люди заменяют первый конструктор Block(QObject *parent = 0); и Block(const QPixmap &img, QObject *parent = 0);, и я не уверен, что это было бы хорошо.

Теперь то, что если я craete в Rectangle класс моей, который наследуется от Block поэтому необходимо также принимать image и position, как его параметры:

Rect(const QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(const QRect &rect, const QPixmap &pixmap = QPixmap(), QObject *parent = 0); 
Rect(const QSize &size, const QPoint &pos = QPoint(), const QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(const QPoint &pos, const QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(int x, int y, int w = 1, int h = 1, QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(int w, int h, QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(const QPoint &pos, int w, int h, QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(int x, int y, const QSize &size, QPixmap &img = QPixmap(), QObject *parent = 0); 
Rect(const Rect &rect); 

Как вы видите, он начинает искать ужасно и чертовски трудно поддерживать. Только представьте Player класс наследующий от Rect и реализации items, health, mana, damage, armor ... Я считаю, что невозможно закодировать эти конструкторы.

Итак, теперь, когда я дал вам эту проблему, я не уверен в этом вопросе; Мне нужны какие-либо советы или рекомендации, которые помогут мне с моими конструкторами, когда использовать параметры по умолчанию и как часто мне нужны все конструкторы и да, просто некоторые советы, которые мешают мне создавать 500 конструкторов для одного класса; должен ли я просто пойти с моим оригинальным примером p.setX(5);?

+0

Вы создаете свои собственные классы здесь или используете классы из библиотеки? –

+0

@MonadNewb Классы, начинающиеся с 'Q', из Qt libararies, остальные мои. –

+0

Один из вариантов: http://en.wikipedia.org/wiki/Builder_pattern –

ответ

2

Если вы создаете свои собственные классы, вы обязательно должны избегать этого экспоненциального взрыва комбинаций конструкторов. Один из способов сделать это - предоставить другие механизмы для создания экземпляров класса. Существует несколько общих Creational Patterns, которые могут выполнять эту задачу для различных конкретных потребностей. Design Patterns - это огромная тема, поэтому я предлагаю вам найти материал для чтения, который поможет вам в этом.

Кроме того, вы, вероятно, должны пересмотреть свой дизайн. Часто, когда у вас есть много параметров для конструктора или нескольких конструкторов с широким спектром параметров, это указывает на то, что класс несет ответственность за слишком много разрозненных вещей. Попробуйте реорганизовать класс на более мелкие, более управляемые куски, каждый из которых отвечает за одну задачу. (См. Single Responsibility Principle.)

+0

Спасибо, я нашел шаблон строителя, который мне лучше всего подходит :-) –

1

Должен быть баланс между простотой и удобством использования. Если у вас есть 500 конструкторов, тогда кому-то придется пробираться через много документов, чтобы найти тот, который им нужно использовать. Вам также придется создать много тестового кода, чтобы убедиться, что все они работают должным образом. Простое эмпирическое правило - «Что наименее, что я могу разоблачить, это самое выгодное»?

Верните свои классы, а затем создайте простейший интерфейс, который может использовать кто-то другой.

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

0

Принимая этот раздел в качестве примера, он может быть значительно упрощена:

Block(const QPixmap &img = Pixmap(), QObject *parent = 0); 
    Block(const QPoint &pos, const QPixmap &img = Pixmap(), QObject *parent = 0); 
    Block(int x, int y, const QPixmap &img = Pixmap(), QObject *parent = 0); 

Удалить эти два:

Block(const QPixmap &img = Pixmap(), QObject *parent = 0); 
    Block(int x, int y, const QPixmap &img = Pixmap(), QObject *parent = 0); 

Если вы хотите на «не в состоянии», вы просто дать ему пустой QPoint:

Block(QPoint(), img); 

И если вы хотите его в x, y, а затем сделать QPoint(x, y)

Block(QPoint(x, y), img, parent); 

(Конечно, вы можете сделать это QPoint pos = QPoint(), так что если вы хотите пустой, который вы можете использовать Block().

Этот же принцип может быть применен к Rect, у вас есть несколько вариантов, которые «почти одинаковы». Замените все варианты тем, что принимает QRect в качестве первого аргумента. Если вы не имеете «иметь» QRect, то, безусловно, его можно создать как временное (и в большинстве случаев это просто «исчезнет»).

Будем надеяться, что это также делает набор фактический конструктор проще, так как вы можете просто сделать

m_rect = rect; 

вместо того, чтобы написать 6 различных форм «У меня есть несколько различных предметов, которые должны быть сделаны в прямоугольник».

Если есть ОЧЕНЬ хорошая причина для добавления другого конструктора, не делайте этого. Просто потому, что код, который вы сейчас работаете, имеет x, y, h и w, не означает, что вы не можете легко сделать это в QRect.

0

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