【问题标题】:Rule of thumb for C++ constructor overloads?C++ 构造函数重载的经验法则?
【发布时间】:2013-07-15 22:09:25
【问题描述】:

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

【问题讨论】:

  • 您是在这里创建自己的类还是使用库中的类?
  • @MonadNewb 以Q 开头的类来自 Qt 库,其余的是我的。
  • 我不同意结束这个问题。诚然,有许多选项可用于解决 OPs 问题,并且在许多情况下,选择主要基于意见。但是,可以在一个相当简洁的答案中列举潜在的解决方案,以及给出每种解决方案的优缺点的资源。为了对这些选项有意见,首先必须知道存在哪些选项。提供这些工具并不违背针对基于意见的问题的 SO 规则的精神,IMO。

标签: c++ constructor overriding class-hierarchy


【解决方案1】:

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

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

【讨论】:

  • 谢谢,我找到了最适合我的构建器模式 :-)
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    以本节为例,可以大大简化:

        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 种不同形式的“我有一些不同的项目,需要做成一个矩形”。

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2011-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多