假设我有一个班级:
class C{
int x_;
int y_;
public:
C(int x, int y): x_(x), y_(y){}
};
然后我想从一个字符串中添加构造,它只会解析x
和y
。在阅读Meyers的书之前,我通常会在课程C
中将其作为另一个构造函数。但是,它也可以使其成为非成员非朋友:
C CFromString(const std::string& s){
int x, y;
//...parse them somehow, throw exception if needed...
return C(x,y);
}
对我来说,这是许多“值类”的标准情况,当有一个“主”构造函数将私有成员设置为提供的值(可能检查正确性)。这些类的其他构造函数通常只是从其他一些参数中计算出这些值。
在我的例子中,使这样的构造函数成为非成员非朋友有什么缺点吗?
更新。我理解Meyers的建议,以及NMNF功能的优势。他的书中没有关于NMNF对象构造的例子,所以我想确保他的建议也适用于建筑。
答案 0 :(得分:5)
如果您开始为每个可能的方式添加构造函数,可以序列化类,那么您将该类与这些序列化方法紧密耦合。
最好将类和序列化程序分开以分离关注点。让课程关注课程的作用以及序列化器的作用(阅读json或其他)
你必须考虑你的类可能是从一个文件,一个套接字,一个json,一个xml,一个数据库......从任意数量的东西中序列化的。
这就是为什么在现代编程中我们使用接口。 我们还使用了工厂模式。
答案 1 :(得分:3)
一个缺点是有点不一致,这是一个美学问题。
您正在调用CFromString
构造函数,而不是调用名为C
的构造函数。它们之间的关系是任意的,只需通过名称中的C
前缀。
如果你使它成为static
成员函数,那么你可以将其称为C::FromString
,使其属于该类。
如果在大型项目中的所有地方都这样做,某种约定会有所帮助。比如说,每当我们有一个类C
,以及一个用于创建C
- s的非成员构造函数时,我们总是将其称为CCons
,然后始终使用重载适用于不同类型。因此,如果我们有一个Widget
类,我们就会调用我们的重载家庭WidgetCons
:
Widget WidgetCons(const std::string &s) { /* make it from string */ }
Widget WidgetCons(int i) { /* make it from int */ }
等等。如果这在我们的250,000行代码库中是一致的,那么只要有人看到任何FooCons
或BarCons
,他们就会确切知道它是什么。