隐式构造函数和默认构造函数之间有什么区别?

34
这个问题很琐碎,但捷克语(我的母语)没有区分隐式和默认,所以我对一些捷克翻译中隐式构造函数和默认构造函数或构造函数调用的区别感到困惑。
struct Test {
  Test(int n=0) { }
};

你能用这些术语描述以下语句的作用吗?
  1. Test t1;
  2. Test t2();
  3. Test t3 = 3;
  4. Test t4(4);
  5. Test t5 = Test(5);

4
建议尽可能使用英文的 C++(一般的技术书籍)。 - David Rodríguez - dribeas
8
我可以翻译。问题是,我的母语让我在思考中混淆了“implicit”和“default”,这主要是一种语言问题。除了需要具备编码技能外,我还需要改变思考的语言,这是一个相当令人兴奋的挑战。 - Jan Turoň
1
我怀疑翻译不同,因为在英语中意思有很大的区别。默认通常被翻译为“výchozí”,而隐式则被翻译为“implicitní”,意思类似于“nevýslovný”。(免责声明:我只懂一点捷克语) - Roman Shapovalov
@RomanShapovalov 这可能是确切的翻译,但 nevyslovený 在捷克语中还有其他具有误导性的含义,因此通常会进行语义翻译或(也许更好的选择)根本不翻译。 - Jan Turoň
1
英文单词“implicit”和“default”并不能清晰地描述这些构造函数的本质。这些词只是标签,作为程序员,我们必须学习它们对应的实际C++行为。如果C++的设计者将这些词用反过来的方式分配,我们的工作也不会有太大的区别。 - Beta
2个回答

46

当谈论构造函数时,术语默认隐式具有以下含义:

  • default constructor is a constructor that can be called with no arguments. It either takes no arguments or has default values for each of the arguments taken.

  • implicit constructor is a term commonly used to talk about two different concepts in the language, the

    • implicitly declared constructor which is a default or copy constructor that will be declared for all user classes if no user defined constructor is provided (default) or no copy constructor is provided (copy). That is, a class with no constructors declared by the user has one default constructor implicitly declared.

    • implicitly defined constructor is a implicitly declared constructor that is used (odr-used1 in the language and for which the compiler will provide a definition.

     

    struct test
    {
        test(int i = 0) { }
        // test(test const&) implicitly declared here
    };
    
    struct test2 { };      // implicitly declared: test2(), test2(test2 const&)
    
    int main()
    {
        test t;
    
        test copy(t);      // causes *definition* of the implicitly
                           // declared copy constructor
    
        test2 t2;          // causes *definition* of test2::test2()
    
        test2 copy2(t2);   // causes *definition* of test2::test2(test2 const&)
    }
    

简单地说,如果可以不带参数调用构造函数,则该构造函数是默认的。如果用户没有提供构造函数但已经声明或定义,则该构造函数是隐式(ly declared/defined)的。

至于具体情况:

Test t1;

使用默认构造函数Test(int = 0),该构造函数不是隐式的。


说明:此句话涉及到IT技术中的C++编程语言中的构造函数相关知识。
Test t2();

这是语言的一种奇怪习惯,它声明了一个不带参数并返回Test对象的函数。

Test t3 = 3;

这被称为复制初始化,相当于从3到Test的隐式转换和从转换结果复制构造t3的组合。这将使用Test(int)构造函数进行转换,然后是隐式定义(和声明)的复制构造函数。注意:编译器可以优化掉复制,但必须验证复制构造函数是否可用(访问说明符)并且可以定义。
Test t4(4);

使用Test(int)构造函数,但在本例中它不是作为一个默认构造函数。
Test t5 = Test(5);

这个例子与Test t3 = 3相当,唯一的区别是在这种情况下从5Test的转换是显式的。在这个例子中并不重要,但如果构造函数被标记为explicit,那么这行代码将编译通过,而t3的情况则会失败。


*) 另一个隐式使用的例子,指的是从3Test的转换在代码中没有明确请求。将其与t5进行比较,t5中程序员明确请求了转换:Test(5)


1
@Leonid: 这个术语在标准中有正式的定义,但实际上它的意思是某个东西调用了它或以其他方式要求它存在。 - Steve Jessop
然后,好像还没有足够的隐式构造函数一样,我们也有了聚合初始化来初始化聚合类型 :-) https://dev59.com/wmMm5IYBdhLWcg3wT9mU - Ciro Santilli OurBigBook.com

5
您似乎混淆了一些术语。一个默认构造函数是不带任何参数的构造函数,隐式调用是直接调用构造函数时的情况。
无论如何:
1)Test t1;
默认构造函数。
2)Test t2();
函数声明。
3)Test t3 = 3;
复制初始化。将调用转换构造函数,从3创建一个临时的Test,并使用复制构造函数创建t3
4)Test t4(4);
直接初始化。直接使用转换构造函数。
5)Test t5 = Test(5);
复制初始化。类似于3)。

@JanTuroň 我会说是1)和3)。请注意,2)根本不调用构造函数。 - Luchian Grigore
《C++ Primer Plus》捷克版声称4)是隐式调用。这是翻译错误吗? - Jan Turoň
1
@JanTuroň 尽管如此,在这种情况下,隐式和显式是非正式使用的,因此它在很大程度上取决于作者对这些术语的含义。 - Luchian Grigore
Test(5)是一个rvalue时,第五个和第三个现在应该是move初始化。 - Puppy
@DeadMG:不符合语言规范... §8.5/13 在形式为 T x=a; 的初始化中[...] 称为 复制初始化 - David Rodríguez - dribeas
显示剩余4条评论

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