在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);
};
只有一个类只有两个属性(position
和image
),我已经得到了四个构造函数,最多只有四个参数。
此外,我经常看到人们用Block(QObject *parent = 0);
和Block(const QPixmap &img, QObject *parent = 0);
替换第一个构造函数,我不确定这是否是一件好事。
现在,如果我创建了自己的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 :(得分: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种不同形式的“我有一些不同的项目,需要制成一个矩形”。
除非有非常好的理由添加其他构造函数,否则不要。仅仅因为您正在处理的代码恰好有x
,y
,h
和w
,并不意味着您无法将其变为QRect
非常容易。
答案 3 :(得分:0)
将初始化程序聚合到单个结构中通常很有用,尽管这并不总是可行的。否则,我同意第一个响应 - 尝试将事物简化为逻辑组等。