C++ 显式调用构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12036037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:49:14  来源:igfitidea点击:

Explicit Call to a Constructor

c++constructor

提问by Tejendra

I know the concept that we can call the Constructor both Explicitlyand Implicitly, and i have tested both the scenarios(generally till now my all purposes got fulfilled by calling constructor Implicitlly), but i was wondering that constructor get called implicitly whenever we create objects,, so what is the main reason behind calling the constructor Explicitly. What advantage or disadvantage it provides when we call constructor Explicitlyover the Implicit Call?

我知道我们可以同时调用构造函数Explicitly和的概念Implicitly,并且我已经测试了这两种场景(通常到目前为止,我的所有目的都是通过调用构造函数来实现的Implicitlly),但我想知道构造函数在我们创建时隐式调用objects,那又如何是调用构造函数的主要原因Explicitly。有什么优势或劣势它提供当我们调用构造函数ExplicitlyImplicit Call

Example

例子

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

Now if i call like

现在如果我打电话给

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

回答by Christian Rau

There are two different problems here, as your definition of explicitand implicitdoes not match the standard definition (on which most of the existing answers are based, being written before you added your example containing your own definition of explicitand implicit).

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

Ok so let's first consider your definition of explicit, which would be (I guess you call it explicitbecause you explicitly write the type name?):

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

integer int1 = integer(0, 100);

versus your definition of implicitwhich would be:

与您对隐式的定义相比:

integer int1(1, 100);

In this case the first "explicit"call really doesn't have any advantage over the second "implicit"call. But there is still a difference. The first one actually creates a temporary using the two-argument constructor, which is then used to create int1using the copy constructor. Although in practice the compiler will usually optimize away this additional copy, it still won't work if your copy constructor is private, whereas the second one only needs the two-argument constructor (you could even see this as disadvantage).

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



But now to the actual standard definitions of explicitand implicit. An explicitconstructor call is any constructor call you, well, explicitly call. Practically speaking, whenever you use the parenthesis syntax ()to create an object you explicitly call a constructor, otherwise it's an implicitconstructor call (so to say, being done behind the scenes by the compiler):

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

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

So the only constructors that can be called implicitlyare the default construtor and any one-argument constructors (including copy and move constructors). A special problem in this regard are one-argument constructors not being copy/move constructors:

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

struct integer
{
    integer(int);
};

This allows the compiler to imlicitlycall the the constructor to convert types, thus any intis implicitly convertible to integer:

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

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

To disallow such behaviour you would have to mark the constructor explicit:

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

struct integer
{
    explicit integer(int);
};

Which only allows it to be called explicitly(e.g. func(integer(42))) (but I guess you already knew this). This has the advantage that it doesn't introduce unnoticed/unwanted conversions behind the scenes, which can lead to all kinds of hard to find problems and ambiguities regarding overload resolution. It is therefore usual practice to mark any conversion constructors (one-argument non-copy/move constructors) explicit, and most probably also the reason why C++11 finally introduced explicitconversion operators.

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



So to sum up, according to your definition and example, there is really no advantage in using integer int1 = integer(1, 100);instead of integer int1(1, 100);, though it makes a (usually irrelevant) difference.

所以总而言之,根据您的定义和示例,使用integer int1 = integer(1, 100);代替实际上没有任何优势integer int1(1, 100);,尽管它会产生(通常无关紧要)差异。

But according to the standard definitions, explicitconstructor calls have plenty advantages over implicitones, since the only way to actually construct an object explicitlyis to use a, well, explicit constructor call, whereas implicit constructor callsare only done behind the scenes in certain situations and only work for zero- and one-argument constructors (as aschepleralready pointed out). And explicitly marking conversion constructors as explicithas the advantage of disallowing unwanted implicit conversions behind the scenes.

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

回答by Aesthete

Calling constructors explicitlyallow you to construct object with arguments, rather than using the default constructor.

显式调用构造函数允许您使用参数构造对象,而不是使用默认构造函数

class Foo
{
  public:
    Foo() {}
    Foo(int bar) : mBar(bar) {}
  private:
    int mBar;
}

Foo f;    // Implicitly constructed with default constructor.
Foo f(7); // Explicitly constructed with argument for 'bar'

回答by Fabian Knorr

There are three ways a constructor can be called:

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

  • Implicitly, by declaring an instance of the type without initializing it
  • Also implicitly, by either initializing an instance with =or by causing an implicit conversion from the argument type to your class.
  • Explicitly calling the constructor, passing arguments.
  • 隐式地,通过声明一个类型的实例而不初始化它
  • 同样是隐式的,通过初始化一个实例=或者导致从参数类型到你的类的隐式转换。
  • 显式调用构造函数,传递参数。

Which of these you can use in a particular context depends on the constructors you're calling.

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

class Foo 
{
    Foo();                                  // 1
    Foo(int a);                             // 2
    explicit foo(const std::string& f);     // 3
    Foo(int c, int d);                      // 4
};
  1. This constructor will be called implicitly when declaring Foo f;. Neverattempt to call a constructor without arguments explicitly, as Foo f();will declare a function!
  2. This one can be called by writing Foo f = 42;or Foo f(42).
  3. The explicitkeyword forbids implicit conversion by writing Foo f = std::string("abc");or function_taking_foo(function_returning_string());.
  4. As there are multiple arguments, the explicit version is the only suitable.
  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. 由于有多个参数,显式版本是唯一合适的。

回答by seattlecpp

I hate to say this, because it is so perverse, but there is an additional way to explicitly call the constructor.

我讨厌这样说,因为它太反常了,但是还有一种额外的方法可以显式调用构造函数。

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

The constructor can be explicitly called on an already-constructed object.

可以在已经构造的对象上显式调用构造函数。

integer i(1,100);
i.~integer();
i.integer::integer(2,200);

Here I've constructed (explicitly) an instance of integer. Then I've explicitly called its destructor. Then I've explicitly called the constructor again. I suppose you might use this idiom in testing. I am not aware of any place in the standard that forbids it. It works in Visual Studio 2010. I haven't tested a really wide range of compilers.

在这里,我已经(显式地)构造了一个整数实例。然后我明确地调用了它的析构函数。然后我再次明确地调用了构造函数。我想你可能会在测试中使用这个习语。我不知道标准中有任何地方禁止它。它适用于 Visual Studio 2010。我还没有测试过非常广泛的编译器。

These calls are explicit for large values of 'explicit'.

这些调用对于“显式”的大值是显式的。

回答by Magnum

If you make a function that takes a reference to a object of your class, and you pass it another type other than your object the constructor of your class will convert that type to an object of your class. Any one argument constructor is treated as a conversion constructor. If you declare that constructor explicit, then passing a different type other than your object to that function will not convert it and the compiler will return an error

如果你创建一个函数来引用你的类的对象,并且你传递给它的不是你的对象的另一种类型,那么你的类的构造函数会将该类型转换为你的类的对象。任何一个参数构造函数都被视为转换构造函数。如果您将该构造函数声明为显式,则将对象以外的不同类型传递给该函数将不会对其进行转换,并且编译器将返回错误