显式调用构造函数

新手上路,请多包涵

我知道我们可以同时调用构造函数的概念 ExplicitlyImplicitly ,并且我已经测试了这两种场景(通常到现在我的所有目的都通过调用构造函数 Implicitly ),但我想知道每当我们创建 objects 时,构造函数都会被隐式调用,那么调用构造函数 Explicitly 的主要原因是什么。当我们调用构造函数 Explicitly 而不是 Implicit Call 时,它提供了什么优点或缺点?

例子

class integer
{
   int m ,n;
 public:
   integer (int x , int y);
};
integer :: integer (int x , int y )
{
   m=x; n = y;
}

现在如果我打电话

integer int1 = integer( 0 , 100); //  Explicit Call
integer int1(1,100); // implicit call

原文由 Tejendra 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

这里有两个不同的问题,因为您对 显式隐式 的定义与标准定义不匹配(大多数现有答案都基于标准定义,在您添加包含您自己的 显式隐式 定义的示例之前编写)。

好的,让我们首先考虑一下您对 explicit 的定义,这将是(我猜您之所以称它为 explicit 是因为您明确编写了类型名称?):

 integer int1 = integer(0, 100);

与您对 隐式 的定义相比:

 integer int1(1, 100);

在这种情况下,第一个 “显式” 调用确实比第二个 “隐式” 调用没有任何优势。但是还是有区别的。第一个实际上使用双参数构造函数创建了一个临时对象,然后使用复制构造函数创建 int1 。尽管实际上编译器通常会优化掉这个额外的副本,但如果您的副本构造函数是私有的,它仍然无法工作,而第二个只需要双参数构造函数(您甚至可以将此视为缺点)。


但现在到了 显式隐式 的实际标准定义。 显式 构造函数调用是任何构造函数调用,好吧,显式调用。实际上,每当您使用括号语法 () 创建一个对象时,您显式调用构造函数,否则它是 隐式 构造函数调用(也就是说,由编译器在幕后完成):

 integer int1;                   // implicit default constructor
integer int1(1, 100);           // explicit two-arg constructor
integer int1 = integer(0, 100); // explicit two-arg constructor, implicit copy constructor

void func(integer);             // function taking by-value
func(int1);                     // implicit copy constructor

因此,唯一可以 隐式 调用的构造函数是默认构造函数和任何单参数构造函数(包括复制和移动构造函数)。这方面的一个特殊问题是单参数构造函数不是复制/移动构造函数:

 struct integer
{
    integer(int);
};

这允许编译器隐式调用构造函数来转换类型,因此任何 int 可以隐式转换为 integer

 void func(integer);
func(42);             // implicit call to int-constructor

要禁止这种行为,您必须标记构造函数 explicit

 struct integer
{
    explicit integer(int);
};

这只允许 显式 调用它(例如 func(integer(42)) )(但我想你已经知道了)。这样做的好处是它不会在幕后引入未被注意到/不需要的转换,这可能会导致各种难以发现的问题和关于重载解决方案的歧义。因此,通常的做法是标记任何转换构造函数(单参数非复制/移动构造函数) explicit ,而且很可能也是 C++11 最终引入 explicit 转换的原因运营商。


因此,总而言之,根据您的定义和示例,使用 integer int1 = integer(1, 100); 而不是 integer int1(1, 100); 确实没有任何优势,尽管它会产生(通常不相关的)差异。

但是根据标准定义, 显式 构造函数调用比 隐式 调用有很多优势,因为 显式 构造对象的唯一方法是使用 _显式构造函数调用_,而 隐式构造函数调用 仅在某些情况下在幕后完成情况,并且仅适用于零参数和一参数构造函数(正如 aschepler 已经指出的那样)。并且将转换构造函数显式标记为 explicit 具有不允许在幕后进行不需要的隐式转换的优点。

原文由 Christian Rau 发布,翻译遵循 CC BY-SA 4.0 许可协议

可以通过三种方式调用构造函数:

  • 隐式地,通过声明类型的实例而不初始化它
  • 同样隐含地,通过使用 = 初始化实例或通过导致从参数类型到您的类的隐式转换。
  • 显式调用构造函数,传递参数。

您可以在特定上下文中使用哪些取决于您正在调用的构造函数。

 class Foo
{
    Foo();                                  // 1
    Foo(int a);                             // 2
    explicit foo(const std::string& f);     // 3
    Foo(int c, int d);                      // 4
};

  1. 在声明 Foo f; 时,将隐式调用此构造函数。 永远不要 尝试显式调用没有参数的构造函数,因为 Foo f();声明一个函数!
  2. 这可以通过编写 Foo f = 42;Foo f(42) 来调用。
  3. explicit 关键字通过编写 Foo f = std::string("abc");function_taking_foo(function_returning_string()); 来禁止隐式转换。
  4. 由于有多个参数,显式版本是唯一合适的。

原文由 Fabian Knorr 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题