1

Sorry for the very bad title but I didn't really know what to write.

I have the following library Neural_Network.h with the class Network in C++:

class Network{
    public:
       struct Settings
       {
           uint32_t                        m_numInputs;
           uint32_t                        m_numHidden;
           uint32_t                        m_numOutputs;
       };
       Network(Settings const& settings);
}

Then, in the Neural_Network.cpp file it is implemented in the following way:

Network::Network( Settings const& settings )
    : m_numInputs( settings.m_numInputs )
    , m_numHidden( settings.m_numHidden )
    , m_numOutputs( settings.m_numOutputs )
{
    assert( settings.m_numInputs > 0 && settings.m_numOutputs > 0 && settings.m_numHidden > 0 );
    InitializeNetwork();
    InitializeWeights();
}

I don't really understand why I do need the: :m_numInputs( settings.m_numInputs ), , m_numHidden( settings.m_numHidden ) , m_numOutputs( settings.m_numOutputs ) after the name of the function. What is its purpose?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
lelli
  • 41
  • 8

3 Answers3

7

It's called an initializer list, and can only be used on constructors. It has roughly the same effect as writing

this->m_numInputs = settings.m_numInputs;
this->m_numHidden = settings.m_numHidden;
this->m_numOutputs = settings.m_numOutputs;

inside the constructor body.

The most important difference is that the initializer list also works on const members and references (and is required in that case, because you can't assign to these in the usual way). This is because the initializer list invokes the constructor of members directly, rather than first default-constructing them and then invoking the assignment operator.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • 2
    It doesn't have the same effect as writing them in the body. In the body you are assigning to them, and in the initializer list, you are constructing them by calling the appropriate constructor (that's why it works for `const` members, you can construct them, but not assign to them). – Rakete1111 Dec 27 '17 at 10:23
  • 1
    @Rakete1111 I was almost waiting for someone to point that out. I didn't want to confuse OP further as they are clearly a beginner. I added the word "roughly" to indicate that something more subtle is going on. – Thomas Dec 27 '17 at 10:27
  • @Thomas may I ask what is the difference? I am not familiar with C++ but I have coded for years, so it would really helpful for me to understand the subtle characteristics of the code I am reading. Thank you very much!!! – lelli Dec 27 '17 at 10:36
  • 2
    @lelli This [Q](https://stackoverflow.com/questions/926752/why-should-i-prefer-to-use-member-initialization-list) might help a bit explain the differences (essentially, it's construction vs assignment in the body). – Rakete1111 Dec 27 '17 at 10:39
  • Also references, for completeness sake. – iksemyonov Dec 27 '17 at 10:48
3

What is its purpose?

To initialize the data members of the class.

This is called an initialization list.

It is very common for a constructor to initialize the data members of its class in the initialization list, rather than in its body.

Read more in Why should I prefer to use member initialization list?


For example, this:

Network::Network(Settings const& settings) : m_numInputs(settings.m_numInputs)

will set the data member m_numInputs to settings.m_numInputs. The same would happen with:

Network::Network(Settings const& settings) {
    m_numInputs = settings.m_numInputs;
}
gsamaras
  • 71,951
  • 46
  • 188
  • 305
2

That's initialization list.

Basically that's the standard C++ syntax to initialize class members in constructions, and that part is executed before the body of constructor.

What that does is to take the three member data of the passed settings argument to initialize the three member data of the Network class.


That being said, I think your class Network is not complete as you show? The Network class you showed doesn't have that data member. I think the complete definition should look like this:

class Network{
    public:
       struct Settings
       {
           uint32_t                        m_numInputs;
           uint32_t                        m_numHidden;
           uint32_t                        m_numOutputs;
       };
       Network(Settings const& settings);

    private:
        unit32_t m_numInputs,
        unit32_t m_numOutputs,
        unit32_t m_numOutputs
};

Side Note: if the fact that data members of Network have the same name with the data members of Settings confuses you, this is really a design decision or purely coincidence, it doesn't have to.

A more simplistic example to show how to use constructor arguments to initialize data members within initialization list.

class Foo {
private:
    int m_x,
    int m_y,

public:
    Foo(int dataA, int dataB);
};

Foo::Foo(int dataA, int dataB): m_x(dataA), m_y(dataB)
{ }
Yong Li
  • 607
  • 3
  • 15