Ok, not a C/C++ expert by any means, but I thought the point of a header file was to declare the functions, then the C/CPP file was to define the implementation.
However, reviewing some C++ code tonight, I found this in a class's header file...
public:
UInt32 GetNumberChannels() const { return _numberChannels; } // <-- Huh??
private:
UInt32 _numberChannels;
So why is there an implementation in a header? Does it have to do with the const keyword? Does that inline a class method? What exactly is the benefit/point of doing it this way vs. defining the implementation in the CPP file?
Ok, not a C/C++ expert by any means, but I thought the point of a header file was to declare the functions, then the C/CPP file was to define the implementation.
The true purpose of a header file is to share code amongst multiple source files. It is commonly used to separate declarations from implementations for better code management, but that is not a requirement. It is possible to write code that does not rely on header files, and it is possible to write code that is made up of just header files (the STL and Boost libraries are good examples of that). Remember, when the preprocessor encounters an #include statement, it replaces the statement with the contents of the file being referenced, then the compiler only sees the completed pre-processed code.
So, for example, if you have the following files:
Foo.h:
#ifndef FooH
#define FooH
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
#endif
Foo.cpp:
#include "Foo.h"
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
Bar.cpp:
#include "Foo.h"
Foo f;
UInt32 chans = f.GetNumberChannels();
The preprocessor parses Foo.cpp and Bar.cpp separately and produces the following code that the compiler then parses:
Foo.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
Bar.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
Foo f;
UInt32 chans = f.GetNumberChannels();
Bar.cpp compiles into Bar.obj and contains a reference to call into Foo::GetNumberChannels(). Foo.cpp compiles into Foo.obj and contains the actual implementation of Foo::GetNumberChannels(). After compiling, the linker then matches up the .obj files and links them together to produce the final executable.
So why is there an implementation in a header?
By including the method implementation inside the method declaration, it is being implicitly declared as inlined (there is an actual inline keyword that can be explicitly used as well). Indicating that the compiler should inline a function is only a hint which does not guarantee that the function will actually get inlined. But if it does, then wherever the inlined function is called from, the contents of the function are copied directly into the call site, instead of generating a CALL statement to jump into the function and jump back to the caller upon exiting. The compiler can then take the surrounding code into account and optimize the copied code further, if possible.
Does it have to do with the const keyword?
No. The const keyword merely indicates to the compiler that the method will not alter the state of the object it is being called on at runtime.
What exactly is the benefit/point of doing it this way vs. defining the implementation in the CPP file?
When used effectively, it allows the compiler to usually produce faster and better optimized machine code.
It is perfectly valid to have an implementation of a function in a header file. The only issue with this is breaking the one-definition-rule. That is, if you include the header from multiple other files, you will get a compiler error.
However, there is one exception. If you declare a function to be inline, it is exempt from the one-definition-rule. This is what is happening here, since member functions defined inside a class definition are implicitly inline.
Inline itself is a hint to the compiler that a function may be a good candidate for inlining. That is, expanding any call to it into the definition of the function, rather than a simple function call. This is an optimization which trades the size of the generated file for faster code. In modern compilers, providing this inlining hint for a function is mostly ignored, except for the effects it has on the one-definition-rule. Also, a compiler is always free to inline any function it sees fit, even if it has not been declared inline (explicitly or implicitly).
In your example, the use of const after the argument list signals that the member function does not modify the object on which it is called. In practice, this means that the object pointed to by this, and by extension all class members, will be considered const. That is, trying to modify them will generate a compile-time error.
It is implicitly declared inline by virtue of being a member function defined within the class declaration. This does not mean the compiler has to inline it, but it means you won't break the one definition rule. It is completely unrelated to const*. It is also unrelated to the length and complexity of the function.
If it were a non-member function, then you would have to explicitly declare it as inline:
inline void foo() { std::cout << "foo!\n"; }
* See here for more on const at the end of a member function.
Even in plain C, it is possible to put code in a header file. If you do it, you usually need to declare it static or else multiple .c files including the same header will cause a "multiply defined function" error.
The preprocessor textually includes an include file, so the code in an include file becomes part of the source file (at least from the compiler's point of view).
The designers of C++ wanted to enable object-oriented programming with good data hiding, so they expected to see lots of getter and setter functions. They didn't want an unreasonable performance penalty. So, they designed C++ so that the getters and setters could not only be declared in the header but actually implemented, so they would inline. That function you showed is a getter, and when that C++ code is compiled, there won't be any function call; code to fetch out that value will just be compiled in place.
It is possible to make a computer language that doesn't have the header file/source file distinction, but just has actual "modules" that the compiler understands. (C++ didn't do that; they just built on top of the successful C model of source files and textually included header files.) If source files are modules, it would be possible for a compiler to pull code out of the module and then inline that code. But the way C++ did it is simpler to implement.
As far as I know, there are two kinds of methods, which can be safely implemented inside the header file.
Inline methods - their implementation is copied to places, where they are used, so there is no problem with double-definition linker errors;
Template methods - they are actually compiled at the moment of template instantiation (eg. when someone inputs a type in place of template), so again there is no possibility of double-definition problem.
I believe, your example fits the first case.
C++ standard quotes
The C++17 N4659 standard draft 10.1.6
"The inline specifier" says that methods are implicitly inline:
4 A function defined within a class definition is an inline function.
and then further down we see that inline methods not only can, but must be defined on all translation units:
6 An inline function or variable shall be defined in every translation unit in which it is odr-used and shall
have exactly the same definition in every case (6.2).
This is also explicitly mentioned in a note at 12.2.1 "Member functions":
1 A member function may be defined (11.4) in its class definition, in which case it is an inline member function (10.1.6) [...]
3 [ Note: There can be at most one definition of a non-inline member function in a program. There may be
more than one inline member function definition in a program. See 6.2 and 10.1.6. — end note ]
GCC 8.3 implementation
main.cpp
struct MyClass {
void myMethod() {}
};
int main() {
MyClass().myMethod();
}
Compile and view symbols:
g++ -c main.cpp
nm -C main.o
output:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 W MyClass::myMethod()
U __stack_chk_fail
0000000000000000 T main
then we see from man nm that the MyClass::myMethod symbol is marked as weak on the ELF object files, which implies that it can appear on multiple object files:
"W"
"w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked
and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error. On some systems, uppercase indicates that a default value has been specified.
Keeping the implementation in the class header file works, as I'm sure you know if you compiled your code. The const keyword ensures you don't change any members, it keeps the instance immutable for the duration of the method call.
Related
Ok, not a C/C++ expert by any means, but I thought the point of a header file was to declare the functions, then the C/CPP file was to define the implementation.
However, reviewing some C++ code tonight, I found this in a class's header file...
public:
UInt32 GetNumberChannels() const { return _numberChannels; } // <-- Huh??
private:
UInt32 _numberChannels;
So why is there an implementation in a header? Does it have to do with the const keyword? Does that inline a class method? What exactly is the benefit/point of doing it this way vs. defining the implementation in the CPP file?
Ok, not a C/C++ expert by any means, but I thought the point of a header file was to declare the functions, then the C/CPP file was to define the implementation.
The true purpose of a header file is to share code amongst multiple source files. It is commonly used to separate declarations from implementations for better code management, but that is not a requirement. It is possible to write code that does not rely on header files, and it is possible to write code that is made up of just header files (the STL and Boost libraries are good examples of that). Remember, when the preprocessor encounters an #include statement, it replaces the statement with the contents of the file being referenced, then the compiler only sees the completed pre-processed code.
So, for example, if you have the following files:
Foo.h:
#ifndef FooH
#define FooH
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
#endif
Foo.cpp:
#include "Foo.h"
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
Bar.cpp:
#include "Foo.h"
Foo f;
UInt32 chans = f.GetNumberChannels();
The preprocessor parses Foo.cpp and Bar.cpp separately and produces the following code that the compiler then parses:
Foo.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
UInt32 Foo::GetNumberChannels() const
{
return _numberChannels;
}
Bar.cpp:
class Foo
{
public:
UInt32 GetNumberChannels() const;
private:
UInt32 _numberChannels;
};
Foo f;
UInt32 chans = f.GetNumberChannels();
Bar.cpp compiles into Bar.obj and contains a reference to call into Foo::GetNumberChannels(). Foo.cpp compiles into Foo.obj and contains the actual implementation of Foo::GetNumberChannels(). After compiling, the linker then matches up the .obj files and links them together to produce the final executable.
So why is there an implementation in a header?
By including the method implementation inside the method declaration, it is being implicitly declared as inlined (there is an actual inline keyword that can be explicitly used as well). Indicating that the compiler should inline a function is only a hint which does not guarantee that the function will actually get inlined. But if it does, then wherever the inlined function is called from, the contents of the function are copied directly into the call site, instead of generating a CALL statement to jump into the function and jump back to the caller upon exiting. The compiler can then take the surrounding code into account and optimize the copied code further, if possible.
Does it have to do with the const keyword?
No. The const keyword merely indicates to the compiler that the method will not alter the state of the object it is being called on at runtime.
What exactly is the benefit/point of doing it this way vs. defining the implementation in the CPP file?
When used effectively, it allows the compiler to usually produce faster and better optimized machine code.
It is perfectly valid to have an implementation of a function in a header file. The only issue with this is breaking the one-definition-rule. That is, if you include the header from multiple other files, you will get a compiler error.
However, there is one exception. If you declare a function to be inline, it is exempt from the one-definition-rule. This is what is happening here, since member functions defined inside a class definition are implicitly inline.
Inline itself is a hint to the compiler that a function may be a good candidate for inlining. That is, expanding any call to it into the definition of the function, rather than a simple function call. This is an optimization which trades the size of the generated file for faster code. In modern compilers, providing this inlining hint for a function is mostly ignored, except for the effects it has on the one-definition-rule. Also, a compiler is always free to inline any function it sees fit, even if it has not been declared inline (explicitly or implicitly).
In your example, the use of const after the argument list signals that the member function does not modify the object on which it is called. In practice, this means that the object pointed to by this, and by extension all class members, will be considered const. That is, trying to modify them will generate a compile-time error.
It is implicitly declared inline by virtue of being a member function defined within the class declaration. This does not mean the compiler has to inline it, but it means you won't break the one definition rule. It is completely unrelated to const*. It is also unrelated to the length and complexity of the function.
If it were a non-member function, then you would have to explicitly declare it as inline:
inline void foo() { std::cout << "foo!\n"; }
* See here for more on const at the end of a member function.
Even in plain C, it is possible to put code in a header file. If you do it, you usually need to declare it static or else multiple .c files including the same header will cause a "multiply defined function" error.
The preprocessor textually includes an include file, so the code in an include file becomes part of the source file (at least from the compiler's point of view).
The designers of C++ wanted to enable object-oriented programming with good data hiding, so they expected to see lots of getter and setter functions. They didn't want an unreasonable performance penalty. So, they designed C++ so that the getters and setters could not only be declared in the header but actually implemented, so they would inline. That function you showed is a getter, and when that C++ code is compiled, there won't be any function call; code to fetch out that value will just be compiled in place.
It is possible to make a computer language that doesn't have the header file/source file distinction, but just has actual "modules" that the compiler understands. (C++ didn't do that; they just built on top of the successful C model of source files and textually included header files.) If source files are modules, it would be possible for a compiler to pull code out of the module and then inline that code. But the way C++ did it is simpler to implement.
As far as I know, there are two kinds of methods, which can be safely implemented inside the header file.
Inline methods - their implementation is copied to places, where they are used, so there is no problem with double-definition linker errors;
Template methods - they are actually compiled at the moment of template instantiation (eg. when someone inputs a type in place of template), so again there is no possibility of double-definition problem.
I believe, your example fits the first case.
C++ standard quotes
The C++17 N4659 standard draft 10.1.6
"The inline specifier" says that methods are implicitly inline:
4 A function defined within a class definition is an inline function.
and then further down we see that inline methods not only can, but must be defined on all translation units:
6 An inline function or variable shall be defined in every translation unit in which it is odr-used and shall
have exactly the same definition in every case (6.2).
This is also explicitly mentioned in a note at 12.2.1 "Member functions":
1 A member function may be defined (11.4) in its class definition, in which case it is an inline member function (10.1.6) [...]
3 [ Note: There can be at most one definition of a non-inline member function in a program. There may be
more than one inline member function definition in a program. See 6.2 and 10.1.6. — end note ]
GCC 8.3 implementation
main.cpp
struct MyClass {
void myMethod() {}
};
int main() {
MyClass().myMethod();
}
Compile and view symbols:
g++ -c main.cpp
nm -C main.o
output:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 W MyClass::myMethod()
U __stack_chk_fail
0000000000000000 T main
then we see from man nm that the MyClass::myMethod symbol is marked as weak on the ELF object files, which implies that it can appear on multiple object files:
"W"
"w" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked
and the symbol is not defined, the value of the symbol is determined in a system-specific manner without error. On some systems, uppercase indicates that a default value has been specified.
Keeping the implementation in the class header file works, as I'm sure you know if you compiled your code. The const keyword ensures you don't change any members, it keeps the instance immutable for the duration of the method call.
I want to use extern keyword for class method in C++. I'm using Visual Studio 2019.
I want to force method inline, using __forceinline(without extern I will get unresolved external symbol). I don't want to put method implementation in this header file, I want put implementation in other .cpp file.
I noticed that method may be inlined automaticly without extern and __forceinline and when method's implementation in .cpp file. How can I force it?
Example code:
class Window {
public:
void Show();
};
That's ok!
class Window {
public:
__forceinline void Show();
};
Gets unresolved external symbol when I calls this function from other CPP.
With extern I gets:
screenshot
For simple functions extern __forceinline works fine:
screenshot
You cannot specify extern for a member function.
The standard clarifies this in [dcl.stc]/5:
The extern specifier can be applied only to the names of variables and functions. The extern specifier cannot be used in the declaration of class members or function parameters.
When you use extern, you say to the compiler that you declare a variable or a function, but without defining it. In the case of member functions, this is not needed: they can always be declared in a class body without being defined:
class A {
public:
void f(); // you can define it in which ever compilation unit (cpp) you want
};
...
// Else where...may be in another cpp
void A::f() {...}
The linker will resolve the symbols when needed.
The inline is not so useful
The standard in [dcl.inline]/2 says that inline is not guaranteed:
The inline specifier indicates to the implementation that inline
substitution of the function body at the point of call is to be
preferred to the usual function call mechanism. An implementation is
not required to perform this inline substitution at the point of call;
Furthermore, [dcl.inline]/6 explains that inline and defined eleswhere is not something meant to work well:
An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case.
(odr says that all the definitions must be exactly the same definition each time)
(in every translation unit means in every cpp or the headers therein included)
On the other side, the global optimizer of some modern compilers is able to achieve similar performance effects than inlined functions, and this accross compilation units (cpp).
Implementation specific forceinline
MSVC 2019 uses inline carefully, making a cost/benefit analysis to decide whether or not to inline.
forceinline allows you to overrule the compiler's judgement. But it comes with all the requirements of the normal inline: so you need to have a definition of the function in the same compilation unit to get it work.
Two things:
You cannot declare a member function as extern. These already have external linkage.
For the compiler to inline a function or method, it has to be defined (as opposed to declared) in the header file. This is so that the compiler can see it when compiling code that calls the function.
So, just put the function body in the header file and drop the extern.
I don't want to put method implementation in this header file, I want put implementation in other .cpp file.
Sounds to me like you just want to have all declarations in one file like this:
This is your window.h- file:
class Window
{
public:
void Show();
};
To have the implementation in another file, you have to use the scope operator.
This is the other window.cpp- file, in which you have the actual implementation of the function:
#include "window.h"
Window::Show()
{
// Your implementation goes here
}
I hope I understood your question right and this helps.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Inline functions in C++
What does the compiler do if I completely implement a class in its header file? A typical example follows:
class MyException
{
public:
explicit MyException(const char* file, int line) file(file), line(line) {};
const char* getFile() const { return file };
int getLine() const { return line };
private:
const char* const file;
const int line;
};
My intention is to use the class like this: throw MyException(__FILE__, __LINE__).
I include this header file into each .cpp file. I suppose the compiler will compile the class as many times as it is defined and include the (identical) machine code into every object file it produces. Now, what will the linker do? I tried a simpler example (without all those pesky const's) and it compiled fine.
What would happen, if instead of a simple class, I implemented a three-screenful-long C function in a header file? And the final question, should I split my example into .h and .cpp files?
All methods will be inline methods. You may loose some minimal time on the overall compilation, but it's ok. As far as I know the only problem that can occur is if you have a static non-cost member variable. Then you have to assign a storage place for it (place a definition and and initial value if you want) presumably in a .cpp or else you will get linker errors about multiple definition.
I've seen header-only projects which had only the main() function in a CPP, but that was heavily templated.
Update for C++17: You can declare static non-const members as inline in your header file since C++17. This makes header-only libraries easily possible without gymnastics like static variables inside inline functions.
A class definition itself doesn't produce any code. It just shows users of the class how it is layed out, so they can generate appropriate code to manipulate it.
It's the member functions of the class that generate code. When you define a member function inside the class definition it gives the function an implicit inline declaration.
A function call can be compiled and linked in one of two ways:
(1) A single copy of the function code with a RETURN assembly instruction at the end can be placed in the image, and a CALL assembly instruction can be placed (along with param passing and return value transfer) at the call site to transfer control to this code.
or
(2) An entire copy of the function implementation can replace the entire function call at the call site.
A function declared inline is a recommendation to the compiler to do it the second way. Further an inline declaration allows the function to be defined in several translation units (so it can be placed in a shared header file). In order for the compiler have the option of implementing the second method, it needs a copy of the function implementation at compile-time. This isn't available if the function implementation is in a foreign translation unit.
It should also be noted that modern compilers do complicated things with functions declared inline. See:
http://gcc.gnu.org/onlinedocs/gcc/Inline.html
When you implement member functions inside a header file, all those functions become implicitly inline.
What does this mean and what implications does it have?
As per,
C++03 Standard §7.1.3/4:
It hints the compiler that substitution of function body at the point of call is preferable over the usual function call mechanism.
Even if the inline substitution is omitted, the other rules(especially w.r.t One Definition Rule) for inline are followed.
So Yes, every translation unit will have the definition of the inline function.This may result in increase in the size of your binaries.
Usually any good mainstream compiler will substitute function body at the point of call if needed, so marking functions inline merely for #1 is not really a good idea but if you want to make your intent clear to users of your class then you can do so by defining the functions within the header or explicitly marking your functions as inline.
Should I split my example into .h and .cpp files?
Yes, that is the usual compilation model that most of the projects use, wherein you separate the interface(.h) from the implementation(.cpp).The interfaces are shared with the users of your code as header files while the implementation is provided in the form of binaries.To some extent this provides a safeguard to your intellectual property.
This is known as the Separation Model.
C++ projects using templates will usually use the Inclusion Model rather than the Separation Model of usual C++ projects.
What's the difference between using the inline keyword before a function and just declaring the whole function in the header?
so...
int whatever() { return 4; }
vs
.h:
inline int whatever();
.cpp:
inline int myClass::whatever()
{
return 4;
}
for that matter, what does this do:
inline int whatever() { return 4; }
There are several facets:
Language
When a function is marked with the inline keyword, then its definition should be available in the TU or the program is ill-formed.
Any function defined right in the class definition is implicitly marked inline.
A function marked inline (implicitly or explicitly) may be defined in several TUs (respecting the ODR), whereas it is not the case for regular functions.
Template functions (not fully specialized) get the same treatment as inline ones.
Compiler behavior
A function marked inline will be emitted as a weak symbol in each object file where it is necessary, this may increase their size (look up template bloat).
Whereas the compiler actually inlines the call (ie, copy/paste the code at the point of use instead of performing a regular function call) is entirely at the compiler's discretion. The presence of the keyword may, or not, influence the decision but it is, at best, a hint.
Linker behavior
Weak symbols are merged together to have a single occurrence in the final library. A good linker could check that the multiple definitions concur but this is not required.
without inline, you will likely end up with multiple exported symbols, if the function is declared at the namespace or global scope (results in linker errors).
however, for a class (as seen in your example), most compilers implicitly declare the method as inline (-fno-default-inline will disable that default on GCC).
if you declare a function as inline, the compiler may expect to see its definition in the translation. therefore, you should reserve it for the times the definition is visible.
at a higher level: a definition in the class declaration is frequently visible to more translations. this can result in better optimization, and it can result in increased compile times.
unless hand optimization and fast compiles are both important, it's unusual to use the keyword in a class declaration these days.
The purpose of inline is to allow a function to be defined in more than one translation unit, which is necessary for some compilers to be able to inline it wherever it's used. It should be used whenever you define a function in a header file, although you can omit it when defining a template, or a function inside a class definition.
Defining it in a header without inline is a very bad idea; if you include the header from more than one translation unit, then you break the One Definition Rule; your code probably won't link, and may exhibit undefined behaviour if it does.
Declaring it in a header with inline but defining it in a source file is also a very bad idea; the definition must be available in any translation unit that uses it, but by defining it in a source file it is only available in one translation unit. If another source file includes the header and tries to call the function, then your program is invalid.
This question explains a lot about inline functions What does __inline__ mean ? (even though it was about inline keyword.)
Basically, it has nothing to do with the header. Declaring the whole function in the header just changes which source file has that the source of the function is in. Inline keyword modifies where the resulting compiled function will be put - in it's own place, so that every call will go there, or in place of every call (better for performance). However compilers sometimes choose which functions or methods to make inline for themselves, and keywords are simply suggestions for the compiler. Even functions which were not specified inline can be chosen by the compiler to become inline, if that gives better performance.
If you are linking multiple objects into an executable, there should normally only be one object that contains the definition of the function. For int whatever() { return 4; } - any translation unit that is used to produce an object will contain a definition (i.e. executable code) for the whatever function. The linker won't know which one to direct callers to. If inline is provided, then the executable code may or may not be inlined at the call sites, but if it's not the linker is allowed to assume that all the definitions are the same, and pick one arbitrarily to direct callers to. If somehow the definitions were not the same, then it's considered YOUR fault and you get undefined behaviour. To use inline, the definition must be known when compiler the call, so your idea of putting an inline declaration in a header and the inline definition in a .cpp file will only work if all the callers happen to be later in that same .cpp file - in general it's broken, and you'd expect the (nominally) inline function's definition to appear in the header that declares it (or for there to be a single definition without prior declaration).
Is there any difference between inline member function (function body inline) and other normal member function (function body in a separate .cpp file)?
for example,
class A
{
void member(){}
};
and
// Header file (.hpp)
class B
{
void member();
};
// Implementation file (.cpp)
void B::member(){}
There is absolutely no difference.
The only difference between the two is that the member inside the class is implicitly tagged as inline. But this has no real meaning.
See: inline and good practices
The documentation says that the inline tag is a hint to the compiler (by the developer) that a method should be inlined. All modern compilers ignore this hint and use there own internal heuristic to determine when a method should be inlined (As humans are notoriously bad and making this decision).
The other use of inline is that it tells the linker that it may expect to see multiple definitions of a method. When the function definition is in the header file each compilation unit that gets the header file will have a definition of the function (assuming it is not inlined). Normally this would cause the linker to generate errors. With the inline tag the compiler understands why there are multiple definitions and will remove all but one from the application.
Note on inlining the processes: A method does not need to be in the header file to inlined. Modern compilers have a processes a full application optimization where all functions can be considered for inlining even if they have been compiled in different compilation units. Since the inline flag is generally ignored it make no difference if you put the method in the header or the source file.
Ignore the word inline here and compiler hints because it is not relevant.
The big practical difference in A and B is when they are used in different libraries.
With the case of A you can #include the header and are not required to link against anything. So you can use this class from different applications / libraries without any special linkage.
With the case of B, you need B.cpp and this should be compiled only into one library / application. Any other library or application that needs to use this class will need to link against the one that contains the actual body of the code.
With some setups / implementations you will need to specifically mark the class as "exported" or "imported" between libraries (for example with Windows you can use dllimport / dllexport and with GNU you can use attribute(visibility="default") )
The first one is implicitly inline, i.e. suggesting the compiler to expand it at the call site.
Other than the inline thing, there's a difference in that you could put more definitions in between the definition of class B, and the definition of the function.
For example, B.cpp might include header files that B.hpp doesn't, which can make a significant difference to the build process for large projects.
But even without a separate translation unit, you can occasionally have a circular dependency that's resolved by separating the definitions. For example the function might take a parameter of a type that's forward-declared before B is defined, then defined by the time the function is defined. If that type uses the definition of B in its own definition, it can't just be be defined before B.