difference between declaration and definition in C++

The examples of declaration in C++:

int i;
int i=0;
extern int i;
int fun();
int fun(){ return 1;}
class A;
class A
{
  int a;
  void fun();
};

The common confusion is some declarations are also definition, e.g.

int i;
int i=0;
int fun(){return 1;}
class A
{
  int a;
  void fun();
};

But other declarations are only declarations, not definition:

extern int i;
int fun();//also called function prototype
class A;//also called forward declaration

C++ requires you have at least a declaration for a name before using it. This seems not necessary in some cases, but just mandatory , for the sake of simplicity for the compiler.

Another confusion is in the definition of a class. The definition of a class does not require the definition of its member functions. You see, in the above examples, the class only includes the declarations of its member functions, not their definitions.

I said you should at least have a declaration for a name before using it, but sometimes, a declaration is not enough, you must have a definition before using it. For example, if you define(implement) a member function outside a class, you should have the definition of the class included beforehand. You should not use the class forward declaration:

class A;
int A::fun()
{
  return 1;
}

You will get the following compiling errors:

error: invalid use of incomplete type ‘class A’

error: forward declaration of ‘class A’

The reason why class definition is needed in this case is that it allows the direct reference of member variables in the definition of member functions. Only after the class is defined can the compiler calculate the address(relative to the beginning of the current object passed as an implicit parameter of the function) of the member variables. You can include the definition of A that is in a header file, in the source file(.cpp file) of the class as follows:

#include "a.h"

int A::fun()
{
  return 1;
}

while a.h contains the definition of A:

class A
{
  int a;
  int fun();
};

And because you’re using(defining) the member function fun of A, you must declare the function inside the definition of A. But that does not mean every member function needs to be defined, for example, the member function fun1 in the following example is not defined, but the definition of class A can be used anywhere and the compilation is successful. But the linker would complain an error if  fun1 is not defined but used.

class A
{
  int a;
  int fun(){return 1;}
  int fun1();
};

The complete definition of a class includes the definition  of its base class. In other words, you must provide the definition of the parent class before the definition of the inherited class. The following example is a wrong usage:

class B;
class A:public B
{
public:
    void fun();
    void fun1();

};

B is considered as an incomplete type and A is then also an incomplete type. But the following a.h works perfectly when you compile a.cpp.

class B;
class A
{
public:
  int a;
  B * b;
  int fun();
};

When the compiler scans to the line B*b, it has already got the declaration of B(as a forward declaration). Although B is not a complete type, the size of b(4 bytes)is determined without a problem(must we know the size of an object before we know the size of the pointer to the object? Absolutely not!).

But if you want to include a member variable of some class(not a pointer to an object of the class) in the definition of the class in question, you should prepare the definition of that class beforehand, because without the definition of that class, the size of the member variable is unknown and the definition of the class in question can not be completed.

Let’s consider the following header file(a.h):

class A:public B
{
public:
  C c;
  int fun();
};

Now you must know you should include the definition of B and C before the compiler scans to the definition of A. But do we include the headers for B(b.h) and C(c.h) in a.h, or in the implementation file a.cpp, to compile a.cpp? To compile a.cpp successfully, both methods work. But if you include the b.h and c.h in a.cpp, you need to arrange the order of the header files carefully, to let the compiler scan b.h and c.h before a.h, e.g.

#include "b.h"
#include "c.h"
#include "a.h"

int A::fun()
{
  return 1;
}

In other words, to use a class, you need to not only include the class’ header file but also include the header files that are needed by the definition of the class. You should dig into the code of the class definition and find out which headers it requires. This is difficult if you are using a third-party class.

The best convention in practice is: only include the header files the current compiling unit is using and let the header files themselves include other header files they are using. That post also talks about other rules to include header file, which are worth memorizing:

  • The class implementation source file always include the class header files as the first include file.
  • The class header file uses class forward declaration of other classes instead of including header files if possible. If the class source file uses the member of those other classes, include their header files in the source file, not in header file. You can include those header files after including the class’s header file and that would not be a problem(now both the forward declaration and the definition of a class occur in the same compiling unit, which is allowed) . This sounds contradictory with previous statement as we talked about including header files in header file. But it is not contradictory in fact. In the header file of a class, you should only include the necessary header files for using  base class and value  member variables. Use forward declaration as much as possible because the class definition is complete with the forward declaration. Most clients may never use the definition of the forward-declared classes and therefore do not need to include their header files. If a client does need the definition of those classes(e.g., for substancing an object), it can include those header files in its source file.

 

 

Leave a Reply