C++总是使用显式构造函数

45
阅读以下博客后:

http://xania.org/200711/ambiguous-overloading

我开始思考,“我是否应该总是显式定义我的构造函数?”

于是我开始阅读更多资料,后来发现了这篇文章:

http://www.sjbrown.co.uk/2004/05/01/always-use-explicit/

这展示了另一个例子,并解释了他背后的想法。当然,这只是一个博主的观点。

我很乐意听取你们中的一些人的想法,你对这种方式有何看法,你在这个主题上的经验以及任何一种方式的几个例子都可以。


2
这个问题不够具体,因为它征询了一个观点。你应该改成要求寻找“硬事实”,例如,“使用编译器自动生成的构造函数是否存在任何缺点?”,或者“在什么情况下需要显式定义构造函数?” - Sergey Kalinichenko
1
虽然我同意dasblinkenlight的观点,但我认为,是的,总是要使用显式声明。这会使你的类在(无意中)被错误使用时更难以使用,这是一件好事。 - stijn
18
oopsi提出的问题非常有用,我真的不明白为什么有些人如此急于关闭这个信息性的问题。我强烈认为Stackoverflow委员会需要审查其政策,并确保有价值的问题不会因为一些拥有少量点数的人有权力这样做而关闭。我认为论坛的整个目的是分享知识,但通过关闭它,我们并没有帮助它。 - samprat
1个回答

69

传统的智慧认为,构造函数仅有一个参数(无论是显式还是通过默认参数隐式传递)时应标记为explicit,除非它们确实定义了一种转换(例如,std::string 可以从 const char* 转换过来)。您已经自己找到了原因,因为隐式转换可能会使生活比必要的更加困难。

也许明显的例外是复制构造函数。或者另一种方式是考虑大多数类型可以从它们自身转换,因此复制构造函数在大多数情况下都没有标记explicit

虽然标记所有其他类型的构造函数为explicit似乎不会有影响,但我反对这样做。因为尽管在C++03中,对于一个接受多个参数的构造函数,explicit没有任何影响,但在C ++ 11中却有影响。用代码表达:

struct foo {
    explicit foo(int i);
    foo(int i, int j);
    explicit foo(int i, int j, int k);
};

foo make_foo()
{
    /* Not C++11-specific: */
    // Error: no conversion from int to foo
    return 42;

    // Okay: construction, not conversion
    return foo(42);

    // Okay: constructions
    return foo(42, 42);
    return foo(42, 42, 42);

    /* C++11 specific: */
    // Error: no conversion from int to foo
    return { 42 };

    // Not an error, not a conversion
    return { 42, 42 };

    // Error! Constructor is explicit
    return { 42, 42, 42 };
    // Not an error, direct-initialization syntax
    return foo { 42, 42, 42 };
}

在一个返回foo的函数中,我个人认为要明确地写出return foo { 42, 42, 42 }显得过于冗长。我不明白使用explicit的好处是什么。我真的希望{ initializers... }语法表示“从给定的初始化器构造对象”,而explicit会妨碍这一点,同时没有任何实际作用。(由于在复制初始化的情况下,{ i }大多数时候确实等同于i,因此我很愿意放弃对它的使用。)

所以我建议养成只对单元一元构造函数使用explicit的习惯,并且仅限于这种情况。


18
谢谢您的赞赏,我对C++11的信息一无所知。 - Tomek
1
回复有点晚了,但是对于构造函数而言,如果除第一个参数外其他参数都是可选的,比如 foo(int a,int b=0, int c=0),这些参数仍然允许从 int 类型进行隐式转换。那么应该将它们标记为 explicit 吗? - dureuill
3
作为班级的写手,你可以自行决定是否要让构造过程显式化。默认参数的作用是使得同一个构造函数可以处理一、两或三个参数的构造过程。要么所有这些构造形式都要显式化,要么全部不显式化。如果需要更精细的控制,则需要将构造函数拆分成更多的重载函数。 - Luc Danton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接