Initialization via constructor

Hi!
I am learning about classes right now and I am getting used to initializing data members like this:

1
2
3
4
5
6
7
8
9
10
11
12
class Cat{
    public:
        Cat(int age){itsAge = age;}
        ~Cat(){}
    private:
        int itsAge;
};

int main(){ 
     Cat Kitty(5); 
     return 0;
}


Now, in another example I read:
1
2
3
4
5
class Cat{
    public:
       Cat():itsAge(5){}
       // ...
};


I only know the operator : from inheritance. Furthermore, how can itsAge take an argument? The constructor syntax is kind of obscure to me. Could please someone explain? Or do I just have to accept it as alternative syntax?

Thanks for your help!
nbt
Last edited on
The data members of your class are constructed before the code inside the constructor's curly braces run. This means that if you initialize data inside the curly braces of your constructor, you are being wasteful - the data has already been initialized once and you are then overwriting that.

The colon after the constructor parameter list lets you specify the initializer list - you can tell the compiler how your data members should be initialized. 95% of the time your constructor body (the curly braces) should be empty, as you should use the initializer list instead.

To understand why this is a big deal, consider the output of this example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <string>

struct SomeType
{
	SomeType()
	{
		std::cout << "SomeType default ctor" << std::endl;
	}
	SomeType(std::string const &)
	{
		std::cout << "SomeType string ctor" << std::endl;
	}
	void setString(std::string const &)
	{
		std::cout << "SomeType setString function" << std::endl;
	}
};

struct BadWay
{
	SomeType a, b, c;
	
	BadWay()
	{
		a.setString("a");
		b.setString("b");
		c.setString("c");
	}
};

struct GoodWay
{
	SomeType a, b, c;
	
	GoodWay()
	: a("a")
	, b("b")
	, c("c")
	{
		//empty
	}
};

int main()
{
	std::cout << "Bad Way:" << std::endl;
	BadWay bad;
	std::cout << std::endl << "Good Way:" << std::endl;
	GoodWay good;
}
Bad Way:
SomeType default ctor
SomeType default ctor
SomeType default ctor
SomeType setString function
SomeType setString function
SomeType setString function

Good Way:
SomeType string ctor
SomeType string ctor
SomeType string ctor
As you can see, the bad way default constructs the data members and then assigns their data later, whereas the good way does it in one go.

Note: with primitive data types, it doesn't matter because they are not default constructed, but you should still get into the good habit of using the constructor initializer list.
Last edited on
Perfect, got it.
Many thanks.
Topic archived. No new replies allowed.