Search code examples
c++classconstructordefault-constructorconstructor-overloading

C++ Classes: Initializing attributes without constructor overloading


Coming from JavaScript and Python, I'm trying to understand the nuances and purpose around C++ class constructors.

In the example below, why is it allowed to initialize attributes without a constructor?

class MyClass {
public:
    int a = 1;
    int b = 2;
};

Does the default constructor include the above definitions/initializations? What is the difference to the following two examples?:

1.

class MyClass {
public:
    int a;
    int b;
    MyClass(){
        a = 1;
        b = 2;
    }
};
  1. JavaScript/Python style (Is this even possible?)
class MyClass {
public:
    MyClass(){
        // Some kind of variable declaration and definition like:
        // this.a = 1;
        // this.b = 2;
    }
};

To me having the option of initialization without a constructor sounds like an overkill and is confusing. In both Python and JavaScript one usually declares and initializes all variables from the constructor, and only from there only.

What is the best practice here?


Solution

  • In the example below, why is it allowed to initialize attributes without a constructor?

    Because C++11 specifically added that feature. See Member initialization.

    Does the default constructor include the above definitions/initializations?

    Yes. This code:

    class MyClass {
    public:
        int a = 1;
        int b = 2;
    };
    

    Is roughly (not exactly) equivalent to this code:

    class MyClass {
    public:
        int a;
        int b;
    
        MyClass() : a(1), b(2) {}
    };
    

    It is actually possible to use both forms of initialization at the same time, eg:

    class MyClass {
    public:
        int a = 1;
        int b = 2;
    
        MyClass() = default;
        MyClass(int a) : a(a) {}
    };
    

    Per Member initialization:

    Non-static data members may be initialized in one of two ways:

    1. In the member initializer list of the constructor.

    2. Through a default member initializer, which is a brace or equals initializer included in the member declaration and is used if the member is omitted from the member initializer list of a constructor.

      If a member has a default member initializer and also appears in the member initialization list in a constructor, the default member initializer is ignored for that constructor.

    The a member is not specified in the default constructor's member initialization list, so it will be initialized with its default value of 1 when a MyClass object is default constructed.

    The a member is explicitly initialized in the converting constructor's member initialization list, so its default value of 1 will be ignored and it will instead be initialized with the caller-provided value when a MyClass object is constructed with an input value.

    The b member is not specified in either constructor's member initialization list, so it will always be initialized with its default value of 2.

    What is the difference to the following two examples?:

    The first example is what you would have to do prior to C++11 (if you are not using the constructor's member initialization list, as shown above).

    The second example is not legal in C++. You can't declare members dynamically, and certainly not from inside a constructor. They have to be declared statically in the class declaration itself.