user630983
user630983

Reputation: 947

Class member initialisation differences

With respect to the class definition for complex number, I saw two types of definitions:

Definition 1

class Complex
{
   private:
      double re;
      double im;

   public:
      Complex(float r,float i) {re = r; im = i;}
      ~Complex() {};
};

Definition 2

class Complex
{
   private:
      double re;
      double im;

   public:
      Complex(double r,double i): re(r), im(i) {}
      ~Complex() {};
 };

The first definition looks OK to me but I do not quite understand the second definition, how does

 Complex(double r,double i): re(r), im(i) {}

work? What does "re( )" mean?

Upvotes: 3

Views: 290

Answers (5)

Dima
Dima

Reputation: 39389

In C++ there is a distinction between assignment and initialization.

a = 5;  // assignment
int b = 6; // initialization
int b(6);  // also initialization

The first version of your class performs assignment inside the body of the constructor. This is more expensive, because the data members re and im are first default-constructed, and then are assigned their values.

In the second version constructor initialization list is used. Here the data members are initialized with the supplied values. This occurs in one step, while default constructor + assignment are two steps. This is more efficient.

Generally, you should prefer initializing your data members in the initialization list to assigning their values inside the body of the constructor. There is a caveat, though. The data member in the initialization list are initialized in the order in which they are declared in the class, not in the order in which they occur in the initialization list. Generally, you want the order of members in the list to match their order of declaration. Otherwise you may end up with very hard to find bugs if the initialization of one data member depends on the value of another.

Upvotes: 1

Wheatevo
Wheatevo

Reputation: 643

First of all, there should be a semicolon after the entire class definition in C++. Otherwise your code will fair to compile.

Anyway, the

Complex(double r,double i): re(r), im(i) {}

is a constructor for the Complex class that simply places the value of r into re and the value of i into im. That is another way of initializing a class's values.

Note that initialization lists like that can be very useful for initializing member classes within a class. Here's an example:

class MemberClass
{
    private:
        int mValue;

    public:
        MemberClass(int value): mValue(value) {}
};

class MemberHolder
{
    private:
        MemberClass mMember;

    public:
        MemberHolder(int value): mMember(value) {}
};

Initialization lists are important for using classes without a default constructor within other classes.

Upvotes: 1

Adam Rosenfield
Adam Rosenfield

Reputation: 400174

It's called an initializer list. In a class's constructor, you can initialize member variables with this syntax. So in this, it's equivalent to putting the statements re = r; im = i; in the body of the constructor.

In the case of POD variables such as int, double, and pointer types, there is no difference between the initializer list syntax and regular assignments in the body. However, for const variables, references, and objects with non-trivial constructors, there is an important difference:

  • For const variables and reference variables, they must be initialized in the initializer list. They cannot be initialized by assigning to them in the body.
  • For objects with non-trivial constructors, how you initialize them in the initializer list corresponds to the constructor that gets called. If you omit the variable, then that object's default constructor gets called (if that object has no default constructor, then that is a compiler error).

Because of that, it's generally recommended that objects with constructors get initialized in the initializer list to avoid redundant work -- if you let its default constructor run by omitting it from the initializer list and then perform some sort of initialization in the constructor body, you're initializing it twice, which can be wasteful.

For example:

class Example
{
private:
    std::string m_string;
public:
    Example()
    {
        // m_string is first initialized by the std::string default constructor,
        // then we assign to it with operator=(const char *).
        // This is inefficient.
        m_string = "test";
    }

    Example(int dummy)
        : m_string("test")
    {
        // Better: we just call the std::string(const char*) constructor directly
    }
};

Upvotes: 4

wkl
wkl

Reputation: 79893

The second form of the Complex constructor uses initialization lists, which are a different (and preferred way) of initialization class members.

The re(...) thing means that member field re should be constructed with whatever arguments it is passed.

As another example - you can create primitives like double and int like this:

double d(5.0d);
int i(5);

Which should explain how the parentheses work in the lists.

Upvotes: 2

John
John

Reputation: 16007

That's an initialization list. It sets the value of re to r and the value of im to i.

Generally you'll see a performance gain by using an initialization list, but it's also important to know when not to use it.

Upvotes: 1

Related Questions