Explicit Call to a Constructor

前端 未结 5 1845
萌比男神i
萌比男神i 2021-02-04 16:16

I know the concept that we can call the Constructor both Explicitly and Implicitly, and i have tested both the scenarios(generally till now my all purp

相关标签:
5条回答
  • 2021-02-04 16:53

    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;. Never attempt 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 explicit keyword 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.
    0 讨论(0)
  • 2021-02-04 17:00

    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

    0 讨论(0)
  • 2021-02-04 17:06

    Calling constructors explicitly allow 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'
    
    0 讨论(0)
  • 2021-02-04 17:07

    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.

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

    0 讨论(0)
  • 2021-02-04 17:15

    There are two different problems here, as your definition of explicit and implicit does 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 explicit and implicit).

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

    integer int1 = integer(0, 100);
    

    versus your definition of implicit which 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 int1 using 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).


    But now to the actual standard definitions of explicit and implicit. An explicit constructor 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 implicit constructor 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 implicitly are 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 imlicitly call the the constructor to convert types, thus any int is implicitly convertible to integer:

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

    To disallow such behaviour you would have to mark the constructor 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 explicit conversion operators.


    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.

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

    0 讨论(0)
提交回复
热议问题