Inlining of member functions

I am reading "Ruminations on c++" and I had a question on something in the Prelude. The authors say
...because these member functions were part of the Trace class definition itself, the C++ implementation would expand them inline, thus making it inexpensive to keep the Trace objects in the program even when no tracing was being done.


So if member functions are part of the class definition, they are expanded inline?

How else would member functions be defined?
Header file Test.h:
1
2
3
4
5
6
7
8
9
10
11
#pragma once

class Test
{
    void DoSomething()
    {
        //Because the definition is here, this method will be inlined.
    }

    void DoSomethingElse(); //No definition, only prototype.  This method won't be inlined unless requested explicitly.
}

Code file Test.cpp:
1
2
3
4
5
6
7
#include Test.h

//Here's the definition of DoSomethingElse():
void Test::DoSomethingElse()
{
    ...
}


If you wanted to insline DoSomethingElse() and still write the definition outside the header, you can apply the inline keyword.
Thanks. So if the method definition is part of the class definition, the method will be inlined in code?
This is according to the C++ definition?
Yes, any function fully defined inside the class definition is inlined. This is part of the C++ standard. If you don't want to inline a function, it must go outside the class definition, usually in a code file like in the example I wrote.

And sometimes we want something inlined but because of circular header referencing would be required, it is impossible to add the definition of the function inside the class' header file. In these cases one moves the definition to a CPP file but then marks the definition with the inline keyword.
Thanks. So if the method definition is part of the class definition, the method will be inlined in code?
This is according to the C++ definition?


If a member function is defined in the class, it behaves as if it were a function with an inline qualifier. There is no guarantee it will actually be inlined in code. There's also no guarantee the compiler won't inline functions without the inline qualifier.


And sometimes we want something inlined but because of circular header referencing would be required, it is impossible to add the definition of the function inside the class' header file. In these cases one moves the definition to a CPP file but then marks the definition with the inline keyword.


If it's possible to define the function in a source file, it's possible to define it in the header file. One simply defines it (with the inline qualifier) after the compiler sees what it needs to make the definition possible.
Cire, this is an example where you must take out the definition of the function.

Parent.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once

#include <vector>

class Child;

class Parent
{
    std::vector<Child*> _children;

public:
    Child* ReturnSpecialChild() const;
    AddChild(Child *newChild)
    {
        _children.push_back(newChild);
    }
};


Child.h:
1
2
3
4
5
6
7
8
9
10
11
12
#pragma once

#include "Parent.h"

class Child
{
    bool _special;

public:
    Child(bool special, const Parent &parent) : _special(special) { parent.AddChild(this); }
    bool IAmSpecial() const { return _special; }
};


Parent.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
#include "Parent.h"
#include "Child.h"

//If you want this inlined, add the inline keyword.
Child* Parent::ReturnSpecialChild() const
{
    for(std::vector<Child*>::const_iterator it = _children.begin(); it != _children.end(); ++it)
    {
        if ((*it)->IAmSpecial()) return (*it);
    }
    return nullptr;
}


As far as I can tell, I cannot write ReturnSpecialChild() inside the Parent.h header because this one requires that the class Child be completely defined because it is using the IAmSpecial() method, only available when the Child class has been fully defined. Conversely, I cannot go the other way around (forward-declaring parent in Child.h) because then I cannot write and compile the constructor of Child that requires that Parent be a fully declared type because it is accessing one of its methods (AddChild()).

So, cire, if you can make this 3-file example into a 2-file example, that would be great, because I can't.
So, cire, if you can make this 3-file example into a 2-file example, that would be great, because I can't.


Include child.h in parent.h. Of course, noting that it can be done is different than suggesting it should be done.
Yes, not what I meant at all. Ideally, one class per header file. Your suggestion eliminates a header file. What I meant is that it is not possible to keep the class definitions in separate header as it is the best practice and still define all methods in each header file.

But yes, strictly speaking we can cut/paste, simulating what the preprocessor does when it proceses #include. This, of course may very well not work in more complex projects with multiple files. I just try to avoid bad advise to someone trying to learn the right way.
Your suggestion eliminates a header file


By include, I meant #include "".
1
2
3
4
5
6
7
8
9
//parent.h
class parent{
//...
};

#include "child.h"
Child* Parent::ReturnSpecialChild() const{
//...
}

http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.6
Note: It's imperative that the function's definition (the part between the {...}) be placed in a header file, unless the function is used only in a single .cpp file. In particular, if you put the inline function's definition into a .cpp file and you call it from some other .cpp file, you'll get an "unresolved external" error from the linker.
If you #include child.h in parent.h, then you cannot #include parent.h in child.h. It would be a circular reference. This is why the Child class is forward-declared in parent.h, to eliminate the circular (and impossible) reference. This is why I thought you were talking about cut & paste. By means of #include is just not possible.
Sure it is.

Parent.h
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
#pragma once

#include <vector>

class Child;

class Parent
{
    std::vector<Child*> _children;

public:
    Child* ReturnSpecialChild() const;
    void AddChild(Child *newChild)
    {
        _children.push_back(newChild);
    }
};

#include "Child.h"

inline Child* Parent::ReturnSpecialChild() const
{
    for(std::vector<Child*>::const_iterator it = _children.begin(); it != _children.end(); ++it)
    {
        if ((*it)->IAmSpecial()) return (*it);
    }
    return nullptr;
}


Child.h
1
2
3
4
5
6
7
8
9
10
#pragma once

class Child
{
    bool _special;

public:
    Child(bool special, Parent &parent) : _special(special) { parent.AddChild(this); }
    bool IAmSpecial() const { return _special; }
};


main.cpp
1
2
3
4
5
6
7
#include "Parent.h"

int main()
{
	Parent p ;
	Child c(true, p) ;
}



But, like I said.. I wouldn't recommend it. These classes are so tightly coupled, I wouldn't have any problem putting the class definitions in the same header. Wouldn't be an issue for moi.


Yes, you're right.
In that case just copy-paste
1
2
3
4
5
//this_is_the_header_that_you_should_include.h
#pragma once
#include "parent.h"
#include "child.h"
#include "parent_implementation.h" 


The other possibility is to put the include outside.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//child.h
#include "parent.h" //outside the guard
#pragma once
class child: public parent{
//...
};

//parent.h
//nothing here, because we don't need others definitions
#pragma once
class child; //forward declaration
class parent{
//...
};

#include "child.h" //it is necessary now
child* parent::return_special_child() const{
//...
}
Ok, I see what you meant. I didn't want my sample to be taken as subject of discussion because it just meant to be a simple sample. True that you can do that, but it is not the general approach. In this particular case of my sample, I can see how the classes are coupled as you mention, but that may be for the particular sample only. This is why I went with the "neutral" approach. Simply because it always works.
Topic archived. No new replies allowed.