Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the reason for initializing fields inside class?

In C++ it is possible to initialize values of class's fields durectly in class, like:

class X
{
  int a = 5;
}

What's the reason for it? Where it can be useful? The default ctor does exactly the same. And it seems like I cannot initialize values with bit masks (int a : 3).

like image 690
yanpas Avatar asked Feb 23 '16 15:02

yanpas


People also ask

What does initializing a class mean?

Initialization. This is when values are put into the memory that was allocated. This is what the Constructor of a class does when using the new keyword. A variable must also be initialized by having the reference to some object in memory passed to it.

What does it mean to initialize a field in Java?

Initializing Instance MembersThe Java compiler copies initializer blocks into every constructor. Therefore, this approach can be used to share a block of code between multiple constructors. A final method cannot be overridden in a subclass.

What is initialization field?

The default value initialization occurs for all fields, including fields that have variable initializers. Thus, when a class is initialized, all static fields in that class are first initialized to their default values, and then the static field initializers are executed in textual order.

Why do we initialize a class in Java?

A class has a class initialization method, which is like a constructor, but we cannot explicitly define the body of this method as we can for a constructor. Java does allow us to write arbitrary code for the initialization of class fields, however, with a construct known as a static initializer.


2 Answers

From the authority (this reads pretty similar to the earlier standard-proposal N2756):

In-class member initializers

In C++98, only static const members of integral types can be initialized in-class, and the initializer has to be a constant expression. These restrictions ensure that we can do the initialization at compile-time. For example:

int var = 7;

class X {
    static const int m1 = 7;        // ok
    const int m2 = 7;                   // error: not static
    static int m3 = 7;              // error: not const
    static const int m4 = var;          // error: initializer not constant expression
    static const string m5 = "odd"; // error: not integral type
    // ...
};

The basic idea for C++11 is to allow a non-static data member to be initialized where it is declared (in its class). A constructor can then use the initializer when run-time initialization is needed. Consider:

class A {
public:
    int a = 7;
};

This is equivalent to:

class A {
public:
    int a;
    A() : a(7) {}
};

This saves a bit of typing, but the real benefits come in classes with multiple constructors. Often, all constructors use a common initializer for a member:

class A {
public:
    A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {}
    A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
    A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
    int a, b;
private:
    HashingFunction hash_algorithm;  // Cryptographic hash to be applied to all A instances
    std::string s;                   // String indicating state in object lifecycle
};

The fact that hash_algorithm and s each has a single default is lost in the mess of code and could easily become a problem during maintenance. Instead, we can factor out the initialization of the data members:

class A {
public:
    A(): a(7), b(5) {}
    A(int a_val) : a(a_val), b(5) {}
    A(D d) : a(7), b(g(d)) {}
    int a, b;
private:
    HashingFunction hash_algorithm{"MD5"};  // Cryptographic hash to be applied to all A instances
    std::string s{"Constructor run"};       // String indicating state in object lifecycle
};

If a member is initialized by both an in-class initializer and a constructor, only the constructor's initialization is done (it "overrides" the default). So we can simplify further:

class A {
public:
    A() {}
    A(int a_val) : a(a_val) {}
    A(D d) : b(g(d)) {}
    int a = 7;
    int b = 5;  
private:
    HashingFunction hash_algorithm{"MD5"};  // Cryptographic hash to be applied to all A instances
    std::string s{"Constructor run"};       // String indicating state in object lifecycle
};
like image 104
Sebastian Mach Avatar answered Oct 23 '22 00:10

Sebastian Mach


Typically, your class definition is in a header file (.h), and your Constructor is in an implementation file (.cpp).

Several times I have seen a bug where the header file has a long list of member variables, and the implementation file initializes them.... but accidentally skips one member, resulting in a bug.

On visual inspection, the code looks right. Lots of members declared; lots of members initialized. The absence of one single value is not obvious.

By putting all the initialization in the same place as the declaration, it is much easier to see if you forgot to initialize one member.


class MySample
{

private:
    int m_CountSamples       { 0 };
    int m_SampleWidth        { sizeof(int) };
    double m_SamplePrecision { 3.14 };
    bool m_fieldIsSorted;                       // It is obvious which field got skipped!
    enumMeaning fieldMeaning { eProductionSample };
};    
like image 25
abelenky Avatar answered Oct 22 '22 22:10

abelenky