1

I am confused about the different syntax used for instantiating an object.

This is my class:

class Object
{

private:

    int field = 0;

public:

    Object() = default; // Just for testing.
    ~Object() = default; // Just for testing.

    Object( const Object& obj ) = default; // Just for testing.

};

This is main method:

int main()
{
    Object b(); // ???
    Object c{}; // default
    Object d = Object(); // default
    Object e = Object{}; // default
    Object f ( Object() ); // ???
    Object g { Object() }; // default
    Object a; // default but avoid
    Object h ( Object() ); // ???
    Object i { Object{} }; // default
    Object j = i; // copy
    Object k( j ); // copy
    Object l{ k }; // copy
    Object m = { l }; // copy
    Object n = ( m ); // copy
    auto o = Object(); // default
    auto p = Object{}; // default
    return 0;
}

I have no problem with the one's marked default or copy. I just want to know, which constructor is called for the one's with ??? as the default one is not called. Has it something to do with () initialization, as it can be seen.

I know this may not be important, but I am suspicious about it.

Can anyone help!

3 Answers3

2

All the three declarations are function declarations, but not variable definition (as you expected).

Object b(); declares a function named b, which takes nothing and returns Object.

Object f ( Object() ); declares a function named f, which takes a unnamed parameter whose type is a function returning Object and taking nothing (i.e. Object()), and returns Object. Similarly for Object h ( Object() );.

As the workaround, for Object b(); you can

Object b;
Object b{}; // since C++11

For Object f ( Object() ); you can

Object f ( ( Object() ) );
Object f ( Object{} );     // since C++11
Object f { Object{} };     // since C++11
Object f { Object() };     // since C++11

See most vexing parse for more.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
2

It's actually not calling any constructor.

When you change the Object class so that all fields are public (so you can view them):

#include <iostream>
class Object
{
public:
    int field = 0;
    Object() = default;
    ~Object() = default;
    Object( const Object& obj ) = default;
};

And then you try to call the empty brackets in main method:

int main()
{
    Object b();
    std::cout << b.field << '\n';
    return 0;
}

You get an error because b is not an Object but a function:

error: request for member ‘field’ in ‘b’, which is of non-class type ‘Object()’

That's why, when you want to call the empty brackets constructor, you have to call it without any brackets:

int main()
{
    Object b;    // this is correct
    std::cout << b.field << '\n';
    return 0;
}
sanitizedUser
  • 1,723
  • 3
  • 18
  • 33
1

You identified all the constructors correctly. The three you aren’t sure about don’t do what you might think.

Object b();
Object f ( Object() );
Object h ( Object() );

All of these are function declarations, not variable definitions.

You declare a function b that has no parameters and returns an Object. Then you declare two functions, f and h, that have a single unnamed parameter and return an Object. The parameter’s type is: function without parameters and returning Object.

This is known as the most vexing parse. Basically the C++ standard says: “If it can be parsed as a function declaration, it must be parsed as a function declaration.” Clang even has a warning for it: -Wvexing-parse.

besc
  • 2,507
  • 13
  • 10