5

As a Java guy trying to learn C++ I'm a little confused as to why you would want to do something like this

class question{
private:
  string ques;

public:
  question(string ques)
}

question::question(string ques){
this->ques = ques; 
};

versus just

class question{
private:
  string ques;

public:
  question(string ques){
   this->ques = ques;
  }
};

Does it have something to with "inline"? I don't quite know what that means either.

Anurag Dhadse
  • 1,722
  • 1
  • 13
  • 26
Dizzykiwi
  • 485
  • 4
  • 10
  • 2
    Nope. Separating the implementation and header files – lakshmen Feb 21 '15 at 05:24
  • "Inline" is a compiler optimisation. Say you have a really short function (eg. to square a number), and it's called in a loop 10000 times. If each call is performed AS a call (ie. a jump, passing parameters, jumping back), that all takes time. Alternatively, the compiler can "inline" it - i.e.. embed the code directly. No change in functionality, but a lot faster . – racraman Feb 21 '15 at 05:31
  • 1
    C era heritage, mostly. In the old times, when memory was at a premium, one preferred one-pass compilers where all names should be declared before they're used (C++ partly relaxes this rule when it comes to class members). And then it's the traditional way of separation between compilation and linking. – ach Feb 21 '15 at 05:44

7 Answers7

7

A big reason is to reduce the number of files that need to be recompiled when implementation changes. Say the interface definition of your question class is stable and won't change much, but you are still working on the implementation of its methods.

If u put all the implementation in the header than all the files that include your header will have to be compiled. The classic examples are template based code which increase the compilation time as their method bodies always have to be visible in header files.

iammilind
  • 68,093
  • 33
  • 169
  • 336
rmccabe3701
  • 1,418
  • 13
  • 31
  • Sorry for revival, what about the very small scripts where all codes fits in one source file? I've encountered this style at very short codes from lecture I'm taking, and wondering if there are some reasons behind it. – jupiterbjy Mar 19 '21 at 06:36
  • 1
    @jupiterbjy for such things I wouldn't bother with putting the implementation outside the class. But that is just me. – rmccabe3701 Oct 15 '21 at 02:29
5

It is a dependency issue.

When you #include one file into another file, the entire content of the included file becomes part of the file that includes it. Remember that #include is a preprocesssor directive. It is processed before the compiler is invoked, which parses the output of the preprocessor. Thus the compiler ends up seeing a single consolidated code with no knowledge that the content may have originated from different sources. The code is compiled as-is from start to end. For example:

Question.h

class question() {
private:
    string ques;

public:
    question(string ques){
        this->ques = ques;
    }
};

A.cpp

#include "Question.h"

void doSomething() {
    question q("something");
    ...
}

B.cpp

#include "Question.h"

void doSomethingElse() {
    question q("something else");
    ...
}

When A.cpp and B.cpp are compiled, the preprocessor merges the content of Question.h into them, and the compiler sees this code:

A.cpp

class question() {
private:
    string ques;

public:
    question(string ques){
        this->ques = ques;
    }
};

void doSomething() {
    question q("something");
    ...
}

B.cpp

class question() {
private:
    string ques;

public:
    question(string ques) {
        this->ques = ques;
    }
};

void doSomethingElse() {
    question q("something else");
    ...
}

So, any changes you make to Question.h affects the content of both A.cpp and B.cpp and thus they both have to be recompiled.

You want to minimize how many files have to be recompiled when you make a change to a given file. By separating the declaration and implementation into separate .h and .cpp files, and then you #include only the .h file in other files, changes you make to the .cpp file do not affect those other files, so they do not have to be recompiled, speeding up compiling time. Only changes to the .h file will cause them to be recompiled. For example:

Question.h

class question() {
private:
    string ques;

public:
    question(string ques);
};

Question.cpp

#include "Question.h"

question::question(string ques) {
    this->ques = ques;
}

A.cpp

#include "Question.h"

void doSomething() {
    question q("something");
    ...
}

B.cpp

#include "Question.h"

void doSomething() {
    question q("something");
    ...
}

When compiled, the compiler sees:

Question.cpp

class question() {
private:
    string ques;

public:
    question(string ques);
};

question::question(string ques) {
    this->ques = ques;
}

A.cpp

class question() {
private:
    string ques;

public:
    question(string ques);
};

void doSomething() {
    question q("something");
    ...
}

B.cpp

class question() {
private:
    string ques;

public:
    question(string ques);
};

void doSomethingElse() {
    question q("something else");
    ...
}

You can make any changes you want to Question.cpp, and only Question.cpp will be recompiled accordingly. A.cpp and B.cpp are not being changed and thus will not be recompiled, unless you change Question.h, in which case they are.

Also, the separation lends itself to the use of precompiled headers, which also helps to speed up compiling time. A PCH consists of #include files that do not change over time, so they can be compiled once and the output cached and reused wherever an #include refers to the PCH. As long as the PCH itself or any of its dependent files are not changed, files that #include the PCH are recompiled only when you change other things they are referring it.

There is another aspect to this separation to consider. If everything were declared and implemented in a single file, and then you #include that file into multiple files, they each receive their own copy of any global variables that are declared. For example:

Question.h

class question() {
private:
    string ques;

public:
    question(string ques){
        this->ques = ques;
    }
};

int myGlobal; // <--

A.cpp

#include "Question.h"

void doSomething() {
    question q("something");
    ...
}

B.cpp

#include "Question.h"

void doSomethingElse() {
    question q("something else");
    ...
}

When compiled, the compiler sees this:

A.cpp

class question() {
private:
    string ques;

public:
    question(string ques){
        this->ques = ques;
    }
};

int myGlobal; // <--

void doSomething() {
    question q("something");
    ...
}

B.cpp

class question() {
private:
    string ques;

public:
    question(string ques){
        this->ques = ques;
    }
};

int myGlobal; // <--

void doSomethingElse() {
    question q("somethingElse");
    ...
}

Now A.cpp and B.cpp both have their own global variable that have the same name. This can cause a linker conflict. It may fail to link altogether. It it may decide to discard one and keep the other. It may decide to keep both. In the latter case, you end up with multiple copies of data, and that can cause subtle inconsistencies at runtime if a given portion of code is manipulating one variable when it is actually expecting to manipulate another variable of the same name. This can be very hard to debug if you are not careful.

By separating the .h and .cpp files, and declaring the global variable as extern in the .h file and defining its memory storage in the corresponding .cpp file, there is only one variable at compile-time, and other files that #include the .h file will merely receive a reference to that single variable. For example:

Question.h

class question() {
private:
    string ques;

public:
    question(string ques);
};

extern int myGlobal; // <--

Question.cpp

#include "Question.h"

int myGlobal = 0; // <--

question::question(string ques) {
    this->ques = ques;
}

A.cpp

#include "Question.h"

void doSomething() {
    question q("something");
    ...
}

B.cpp

#include "Question.h"

void doSomethingElse() {
    question q("something else");
    ...
}

When compiled, the compiler sees this:

Question.cpp

class question() {
private:
    string ques;

public:
    question(string ques);
};

extern int myGlobal; // <--

int myGlobal = 0; // <--

question::question(string ques) {
    this->ques = ques;
}

A.cpp

class question() {
private:
    string ques;

public:
    question(string ques);
};

extern int myGlobal; // <--

void doSomething() {
    question q("something");
    ...
}

B.cpp

class question() {
private:
    string ques;

public:
    question(string ques);
};

extern int myGlobal; // <--

void doSomethingElse() {
    question q("something else");
    ...
}

The linker (not the compiler) is responsible for resolving those external references as needed so there is only one variable in the final executable that all relevant code is accessing.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • #include is not a precompiler directive - there is no such thing in standard C++. It is a preprocessor directive. Also, features such as precompiled headers and (even) the linker are implementation details. The standard does not require such things (although it doesn't prevent them) and there are real-world implementations which don't have them. – Rob Feb 21 '15 at 07:53
  • Minor typo mentioning the *precompiler*. And yes, PCHs are just an optimization, not a requirement. But in the real world, the majority of C++ toolchains you are likely to encounter and use are implemented with separated compiler and linker. – Remy Lebeau Feb 21 '15 at 08:01
  • No need to generalise. As a matter of fact, I have used toolchains both with and without separated compiler and linker. Numerically, more of them did not have a separate linker (whether one counts multiple versions/releases/bug-fixes of particular products/suites or not). – Rob Feb 21 '15 at 08:10
0

In C++ by default the method defined withing class consider as inline but you can also make function inline by defining outside the class.The defining function in the class does not mean compiler will consider as inline always.

To consider function to be inline there are conditions functions must met.You can refer some C++ book for the conditions.

Its provision given by C++ that you can declare method in class and define outside, this thing may be provided to make code more readable and manageable.

rpk
  • 70
  • 9
0

In java we don't have header file but there are interfaces in java. But in C++ and C we have header file with extension .h /.hpp. So in C++, you have the advantage of keeping declaration and definition or interface and implementation in two different files. If you are a library developer you have to include the header files in the package of library . So the users of your library will get interface information for further use from header files.

If you define a definition/implementation of a function inside a class declaration system may decide to consider it as an inline function depends on certain criteria in C++. You can read answers on inline criteria here What is the criterion to be inline

Community
  • 1
  • 1
Steephen
  • 14,645
  • 7
  • 40
  • 47
0

In C++ you sometimes want to put the definition in a .cpp or .cc file because you want to control where the object code is generated.

This is especially true if you are writing a shared library that needs to maintain a stable ABI. In fact, for stable ABI do not define anything in the header.

Because if you put code in the header, and allow the compiler to define default constructors, destructors and assignment operators, it will put them into random locations (well, random to people who aren't experts with the linker).

Java's class module system makes more sense, really. But C++ has a lot of baggage from C and this is part of it.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
0

To reduce compile-time coupling.

C++ compilation takes way more time than Java's. That's the reason we want to limit the code a compiler needs to see when compiling an implementation.

You will encounter some other techniques to accomplish this, like the pimpl-idiom, where an class entirely hides it's implementation in a pointer-to-some-hidden-class.

// SomeClass.h - only the visible interface
class SomeClass {
public:
     void foo();
     ...
private:
     class Impl;
     std::unique_ptr<Impl> impl;
};

/// SomeClass.cpp
class SomeClass::Impl {
public:
      void foo() {...}
};

SomeClass::SomeClass()
: impl(std::make_unique<Impl>())
{}

void SomeClass::foo() { impl->foo(); }
xtofl
  • 40,723
  • 12
  • 105
  • 192
0

All 6 (at the time of writing) answers here give part of the answer, so my answer is going to try to summarize all of the reasons in one answer.

Before I start, a refresher on terminology. To declare a variable, function, or method in C++ means to say that it exists and describe it's type, whereas to define it means to provide it's implementation.

So in no particular order:

  1. To make it possible to separate the declaration of methods from the definition. From a software engineering point of view, this is a good idea - you can specify the interface to your class separately from it's implementation.

  2. To reduce compile times. Typically the interface to your class, containing the class declaration, is placed in a .h (header) file and the definition (implementation) is placed in a .c file. One of the key benefits of this is that it allows the different components to be compiled separately, which in turn reduces the number of files that need to be recompiled when one of them changes.

    As a side note: it is not mandatory to put only declarations and no definitions in a header file. There are some circumstances where you want definitions in a header file - see below for more.

  3. To allow definition of an ABI for a library which other code can link to. Components can be placed into shared libraries, which can then be called from completely separate programs. When writing a program that uses such a library, you include the header file so that the compiler will know about the classes, methods, functions etc that exist in the library. But this header file must not include any of the actual definition of the class, otherwise small revisions to the library would break code that is using it.

  4. To allow mutual interdependence between classes, without requiring a multi-pass compilation process.

    Suppose Class A has a method which calls a method of class B, and class B has a method that calls class A. If you had declared class A first, then the compiler would not yet have knowledge of the methods of class B at the time it is compiling the definition of the methods in class A. Re-ordering the methods in the file would not help as then the reverse would apply.

    Placing the definition of the methods after both of the class declarations means that the compiler knows of the existence of all of the methods in both classes before it has to compile the definitions of either.

You might now be wondering, with these solid reasons, why does C++ even allow definition of methods inside the class declaration. Well, aside from convenience, there is a key reason: in some cases, you want it to be possible for the compiler to 'inline' a method. This means, at the site of a function call, instead of generating machine code to perform a function call, it instead inserts the instructions of the function itself. This can be beneficial if the function is very small, for example, so that the overhead of actually calling a function is not really warranted.

To do this, the definition of the function needs to be known at every point where it will be called. Since the call sites might be in completely different compilation units (.c files) you need to put the actual definition of the function inside the header, so that the compiler will have access to it just by virtue of including the header.

There are two ways to do this:

  1. Define the function inside the class declaration:

    class foo {
    
    public:
        void bar() {
          doSomething();
        }
    
    };
    
  2. Define the function outside the class declaration, but still inside the header file:

    class foo {
    
    public:
        void bar();
    }
    
    void inline foo::bar() {
        doSomething();
    }
    

Note that in the second case, the keyword 'inline' tells the compiler that the method can be inlined. In the first case, the method is implicitly marked as inline-able by virtue of being defined inside the class declaration.

In both cases, the compiler does not have to inline it - it is up to the compiler to ultimately decide this.

The inline keyword (implicit or otherwise) has another effect: it sidesteps the 'one definition rule' in C++ which states that there can only be one definition of a function. Otherwise, there would be problems in creating a program where multiple .c files referenced the same header, as they would all include definitions of the same function.

In cases where I want a method to be inline-able, I normally use the first style unless there are cross dependencies as described above. Also, I avoid writing long functions in the header using either style - if it is a long function it is unlikely that inlining will have any benefit anyway.

Note also that inlining functions makes your code more brittle to changes. You should not make use of inlining for any functions you expose in a library you are writing, for example.

harmic
  • 28,606
  • 5
  • 67
  • 91