1

在 C++ 中,我经常(几乎总是)遇到构造函数的问题;我永远不确定如何使用参数,最终我将最终只为每个类使用无参数构造函数。然后我将在每个实例定义之后使用 setter。例如:

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

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

我最终使用“更糟糕”的方法的原因是因为有些类需要太多参数,并且有太多不同的可能性来构造它们,所以我的想法变得一团糟,我不再知道我应该做什么。这是我最近制作的一个类的示例(它使用 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);
};

只有一个只有两个属性(positionimage)的类,我已经得到了四个构造函数,最多接受四个参数。Block(QObject *parent = 0);此外,我经常看到人们用and替换第一个构造函数,Block(const QPixmap &img, QObject *parent = 0);我不确定这是否是一件好事。

那么,如果我创建一个Rectangle自己的类,它继承自Block所以它也需要接受imageposition作为它的参数:

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);例子吗?

4

4 回答 4

2

如果您正在创建自己的类,则绝对应该避免构造函数组合的这种指数爆炸式增长。一种方法是提供其他机制来创建类的实例。有几种通用的创建模式可以满足各种特定需求的目的。设计模式本身就是一个巨大的话题,所以我建议你找一些阅读材料来帮助你。

此外,您可能应该重新审视您的设计。通常,当您为一个构造函数或多个具有多种参数的构造函数有很多参数时,这表明该类负责太多不同的事情。尝试将类重构为更小、更易于管理的块,每个块负责一个任务。(参见单一职责原则。)

于 2013-07-15T22:14:38.760 回答
1

必须在简单性和可用性之间取得平衡。如果您有 500 个构造函数,那么有人将不得不翻阅大量文档才能找到他们需要使用的构造函数。您还必须创建大量测试代码以确保它们都按预期工作。一个简单的经验法则是——“我能暴露的最少的是什么,那是最有益的”?

版本化你的类,然后创建其他人可以使用的最简单的接口。

对于具有两个属性(块和位置)的示例,您不能通过提供四个构造函数来为该类的用户提供太多选择。给出构造函数的一个版本——任何使用该类的人都会知道该做什么——考虑到他们的特定情况。

于 2013-07-15T22:17:57.280 回答
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,那么肯定可以将其创建为临时的(在大多数情况下,它只会“消失”)。

希望这也使 set 实际构造函数更简单,因为您可以这样做

m_rect = rect; 

而不是必须写 6 种不同形式的“我有一些不同的项目,需要做成一个矩形”。

除非有很好的理由添加另一个构造函数,否则不要。仅仅因为你现在正在处理的代码恰好有x, y, h, 和w, 并不意味着你不能QRect很容易地把它变成一个。

于 2013-07-15T22:38:24.407 回答
0

将初始化程序聚合到单个结构中通常很有用,尽管这并不总是可行的。否则,我同意第一个回应 - 尝试将事物简化为逻辑组等。

于 2013-07-17T01:45:55.633 回答