C ++构造函数重载的经验法则?

时间:2013-07-15 22:09:26

标签: c++ constructor override class-hierarchy

在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);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并实施itemshealthmanadamagearmor ...... 我发现编写这样的构造函数是不可能的。

所以现在我已经把问题告诉了你,我不确定这个问题;我需要任何提示或技巧来帮助我构建我的构造,何时使用默认参数以及我需要多长时间使用所有构造函数,是的,只是一些提示,以防止我为一个类创建500个构造函数;我应该使用我原来的p.setX(5);示例吗?

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

简单性和可用性之间必须保持平衡。如果你有500个构造函数,那么有人将需要通过大量的文档来找到他们需要使用的文档。您还必须创建大量测试代码,以确保所有测试代码都按预期工作。 一个简单的经验法则是 - “我能揭露的最少的是什么,这是最有益的”?

对您的类进行版本控制,然后创建其他人可以使用的最简单的界面。

对于具有两个属性(块和位置)的示例,您可以通过提供四个构造函数为该类用户提供更多选择。给出一个版本的构造函数 - 根据具体情况,任何使用该类的人都会知道该怎么做。

答案 2 :(得分: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,肯定可以创建一个临时(在大多数情况下,这将只是“消失”)。

希望这个ALSO使得set的实际构造函数更简单,因为你可以做到

m_rect = rect; 

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

除非有非常好的理由添加其他构造函数,否则不要。仅仅因为您正在处理的代码恰好有xyhw,并不意味着您无法将其变为QRect非常容易。

答案 3 :(得分:0)

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