Acestea sunt niste reguli pentru impartirea codului C++ in fisiere. Ele ar trebui sa raspunda la intrebarea: ce trebuie pus in fisierele header (.h) si ce trebuie pus in fisierele de implementare (.cpp).
Trebuie spus de la inceput ca aceste reguli nu sunt absolute ! Ele sunt doar niste sugestii care au dovedit ca duc la performante optime din punct de vedere a codului generat, a vitezei de compilare ...
Majoritatea proiectelor C++ le folosesc si sunt folosite de catre majoritatea programatorilor.
1. Fisierele header pot contine:
a. Directive de includere:
Exemplu:
#include "my_header.h"
b. Macro definitii
Exemplu:
#define BOOL bool
c. Diverse directive de preprocesare
d. Declaratii si definitii de tipuri
Exemplu:
typedef my_struct * my_struct_ptr;
struct my_struct
{
....
};
enum my_enum
{
....
};
class my_class
{
private:
int a;
int b;
public:
my_class(int, int);
void MyMethod1(int);
};
Important: Functia membru MyMethod NU se implementeaza in fisierul header ci intr-un fisier cpp, cu exceptia cazului in care se doreste ca aceasta functie sa fie inline. Daca functia MyMethod se doreste a fi inline, SE POATE implementa in fisierul header
Mai multe despre functii inline vom discuta ceva mai incolo.
e. Declaratii de functii
Fisierele header ar trebui sa contina DOAR declaratii de functii. Ele nu ar trebui sa contina implementarea functiilor respective, cu exceptia cazurilor in care respectivele functii sunt inline (precum am vazut ca punctul anterior) sau sunt template (precum vom vedea mai incolo)
Exemplu:
extern int max(int x, int y);
Implementarea functiei max ar trebui sa fie intr-un fisier *.c sau *.cpp
Este GRESIT sa implementam functia max in header
f. Definitii de functii inline
Functiile inline se pot implementa in fisiere header.
Exemplu:
inline int max(int x, int y)
{
if (x > y)
return x;
return y;
}
O clasa poate avea functii membre inline. Ele se pot defini in header precum urmeaza
class my_class
{
private:
int x;
int y;
public:
my_class(int, int);
...
void set_x(int a) { x = a;}
...
};
Fuctia set_x este implementata chiar in interiorul clase. In cazul acesta este IMPLICIT inline.
SAU
class my_class
{
private:
int x;
int y;
public:
my_class(int, int);
...
inline void set_x(int a);
...
};
Si mai jos, in cadrul aceluiasi header:
void my_class::set_x(int a)
{
x = a;
}
g. Definitii de functii template
Functiile template se pot implementa in fisiere header.
Exemplu:
template
T max (const T& x, const T& y)
{
if (x > y)
return x;
return y;
}
Nota: mai sus, cuvantul cheie "class" poate fi substituit cu "typename", adica sa avem template
...
h. Clase template
Un fisier header poate contine clase template. El poate contine (si este recoamandat sa contina) si implementarea functiilor membre ale clase template.
Exemplu:
template
class MyClass
{
private:
T x;
T y;
public:
MyClass (const T& a, const T& b) { x = a; y = b;}
T func(const T& x, const T& y);
};
template
T MyClass::func(const T& x, const T& y)
{
if (x > y)
return x;
return y;
}
Aici, functia membra "func", apartinad clase "MyClass" este implementata in acleasi fisier header unde este definita clasa "MyClass".
i. Declaratii de date
Exemplu:
extern int x;
j. Declaratii de tipuri, forward declaration
Exemplu:
class x;
Aici x este o declaratie a unei clase. Clasa poate fi definita mai jos in cadrul aceluiasi header sau in alt header.
k. Definitii de constante
Exemplu:
const double my_const = 0.1;
l. Un fisier header NU ar trebui sa contina directive "using" pentru namespace-uri, in scope-ul global.
Concluzie:
1. Sa zicem ca implementati o functie care nu este membru al unei clase
- Functia se doreste a fi inline ? Daca da atunci declarati functia ca inline si definiti-o intr-un header
- Functia este template ? Daca da, atunci definiti functia intr-un header
- Functia nu e nici inline nici template ? Atunci declarati functia intr-un header si definiti-o intr-un fisier *.c sau *.cpp. Respectivul fisier de implementare (ca si alte fisiere in care se foloseste functia) trebuie sa includa header-ul in care functia este declarata
2. Sa zicem ca implementati o noua clasa
- Clasa este template ? Daca da, functiile sale membru trebuie sa fie implementate in acelasi header in care este definita clasa (sau in alt header inclus de catre acesta)
- Clasa nu este template ? In cazul asta, implementati functiile membru care se doresc a fi inline in acelasi header in care este definita clasa (sau in alt header inclus de catre acesta), iar functiile membru non-inlined se implementeaza intr-un fisier *.cpp, care include respectivul header
Putin mai mult despre functiile inline. Scopul folosirii functiilor inline este de a mari viteza de excutie a codului. Compilatorul substituie apelul unei functii inline cu implementarea propriu-zisa a functiei. O functie ar trebui sa fie declarata inline in cazul in care are dimensiuni reduse si e apelata relativ des. Daca o functie are dimensiuni mari si e facuta inline, aceasta poate duce la cresterea semnificativa a codului, in cazul in care functia este apelata des. In cazul extreme, poate duce si la scaderea vitezei de executie a codului, din cauza ca se pot genera cache-miss-uri suplimentare ! Se recomanda se se faca profiling pe cod, inainte de a face o functie inline si dupa.
In acest moment, unii pot avea nelamuriri in privinta functiilor/claselor template. Mai precis: de ce se recomanda ca functiile membru ale unei clase template sa fie implementate in header, chiar daca nu sunt inline ?
Daca exista astfel de nelamuriri, atunci trebuie sa discutam mai mult despre clase template si voi deschide un topic nou pe aceasta tema.