Il faut une definition d'une fonction inline dans toute unite de compilation qui l'utilise. Donc la definition ne peut etre cachee que pour des fonctions qui ne sont pas utilisees par les clients.
Version imprimable
D'accord. Donc, si j'ai bien compris, on peut finalement cacher une partie des implémentations en imbriquant des fonctions inline comme ceci :
Le client verra effectivement l'implementation de "devoile" mais l'implémentation de "cache" pourra en revanche ne pas lui être montrée. Non?Code:
1
2
3
4
5
6
7 class Foo { public:int devoile(int); private:int cache(int); }; inline int Foo::devoile(int i){return cache(i);} // ne peut pas être caché inline int Foo::cache(int i){return i;} // peut-être caché
Mais si l'on veut permettre une utilisation des fonctions en ligne par les programmeurs client tout en leur cachant le code source de ces mêmes fonctions, comment peut-on s'y prendre ? Si la définition de la fonction inline doit être présente dans chaque unité de compilation on ne peut déclarer une fonction membre dans le fichier d'entête et fournir sa définition inline dans un fichier objet déjà compilé. Le résultat côté programme client sera forcément un appel de fonction. On est donc obligé de fournir le code des fonctions que l'on souhaite mettre en ligne. C'est cela qui me dérange...Citation:
Ce qu'il faut, c'est qu'une fonction inline soit definie (et de la meme maniere) dans toutes les unites de compilations qui l'utilisent. Le plus simple est de mettre la definition dans le .hpp qui la declare, mais ce n'est en rien obligatoire. Il est relativement courant quand on adopte l'organisation une classe=un .hpp et un .cpp de ne definir dans le .hpp que les fonctions inline publiques et protegees et definir dans le .cpp les fonctions inline privees qui ne sont pas utilisees par les fonctions inline presentes dans le .hpp.
A moins (je ne sais pas si ça fonctionne...) de déclarer une extern class et de définir celle-ci dans un fichier objet. Est-ce que ce genre de "manipulation" est possible ?:question:
On ne peut pas sauf à fournir les fichiers compilés avec une option du genre lto et donc à imposer aux clients cette option.
En passant, les fonctions qui ont un intérêt à être inline sont souvent triviales, quel est l'intérêt de les cacher? Je comprends un peu mieux le problème pour les templates, où il n'y a pas non plus de solution dans le cadre du langage. Mais même alors, l'absence généralisée de solution en dehors me fait penser que ce n'est pas un trop gros problème en pratique. Si ce l'était, les compilateurs fourniraient quelque chose depuis longtemps (ça se fait bien dans d'autres domaines).
Comme j'ai dit que j'allais refaire un test, le voici :
L'implémentation d'une fonction dans un fichier à part :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 // carchain.h : Header classe chaine de caractères #include <string.h> #include <iostream> #ifndef CARCHAIN_H #define CARCHAIN_H class CarChain{ char* tab; public: CarChain(int a); void print(); void load (char *); }; inline CarChain::CarChain (int a){ tab = new char[a]; memset(tab,' ',a); } inline void CarChain::print(){ std::cout << tab << std::endl; } #endif
Le programme principal :Code:
1
2
3
4
5
6
7
8
9
10 // carchain.cpp implémentation de Carchain::load #include "carchain.h" #include <string.h> #include <iostream> #ifdef line inline void CarChain::load (char * src){memcpy(tab,src,strlen(src));} #else void CarChain::load (char * src){memcpy(tab,src,strlen(src));} #endif
Le résultat des deux compilations :Code:
1
2
3
4
5
6
7
8
9
10 // exo7.cpp : fonction inline #include "carchain.h" int main(){ CarChain test(54); test.load("test et retest"); test.print(); return 0; }
Code:
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
29
30
31
32
33
34
35 mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> g++ -c carchain.cpp -Wall -Dline mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> ls -l total 20 -rw-r--r-- 1 mikmak users 272 28 août 18:42 carchain.cpp -rw-r--r-- 1 mikmak users 381 28 août 18:43 carchain.h -rw-r--r-- 1 mikmak users 2168 28 août 18:45 carchain.o -rw-r--r-- 1 mikmak users 148 27 août 19:54 exo7.cpp -rw-r--r-- 1 mikmak users 3387 27 août 19:59 exo7.s mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> g++ -o exo7 exo7.cpp carchain.o -Wall -O1 exo7.cpp: In function ‘int main()’: exo7.cpp:8:29: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] /tmp/ccrSTqNa.o: In function `main': exo7.cpp:(.text+0x49): undefined reference to `CarChain::load(char*)' collect2: ld returned 1 exit status mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> ls -l total 20 -rw-r--r-- 1 mikmak users 272 28 août 18:42 carchain.cpp -rw-r--r-- 1 mikmak users 381 28 août 18:43 carchain.h -rw-r--r-- 1 mikmak users 2168 28 août 18:45 carchain.o -rw-r--r-- 1 mikmak users 148 27 août 19:54 exo7.cpp -rw-r--r-- 1 mikmak users 3387 27 août 19:59 exo7.s mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> g++ -c carchain.cpp -Wall mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> g++ -o exo7 exo7.cpp carchain.o -Wall -O1 exo7.cpp: In function ‘int main()’: exo7.cpp:8:29: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> ls -l total 32 -rw-r--r-- 1 mikmak users 272 28 août 18:42 carchain.cpp -rw-r--r-- 1 mikmak users 381 28 août 18:43 carchain.h -rw-r--r-- 1 mikmak users 2440 28 août 18:46 carchain.o -rwxr-xr-x 1 mikmak users 12211 28 août 18:46 exo7 -rw-r--r-- 1 mikmak users 148 27 août 19:54 exo7.cpp -rw-r--r-- 1 mikmak users 3387 27 août 19:59 exo7.s mikmak@linux-uf9h:~/Devel/C++/eckel/p246/exo7> ./exo7 test et retest
Qu'est ce une option lto ?
Oui en effet, il s'agit la plupart du temps de fonction d'initialisation, restitution de données etc...Citation:
En passant, les fonctions qui ont un intérêt à être inline sont souvent triviales, quel est l'intérêt de les cacher?
Le seul intérêt de les cacher serait dans l'exemple du cheshire que j'ai donnée au début tiré de "penser en c++" de Bruce Eckel. Dans cet exemple les données mêmes de la classe sont cachées au programmeur client, celui-ci ne voit qu'un pointeur vers une structure dont les détails font partie du fichier d'implémentation. Ce qui nous oblige a renoncer aux fonctions inline même pour le constructeur d'une telle classe, puisque montrer la façon dont le constructeur s'y prend pour initialiser la structure dévoilerai en même temps l'organisation de la structure.
Je n'en suis pas encore aux templates dans mon apprentissage, mais j'examinerai bientôt ce point.Citation:
Je comprends un peu mieux le problème pour les templates, où il n'y a pas non plus de solution dans le cadre du langage.
Oui c'est ce qui m'a fait croire au début qu'il existait peut-être une solution à ce problème. Comme tu l'as dit précédemment le fait que les fonction inline sont la plupart du temps triviales réduit d'autant son importance.Citation:
Mais même alors, l'absence généralisée de solution en dehors me fait penser que ce n'est pas un trop gros problème en pratique. Si ce l'était, les compilateurs fourniraient quelque chose depuis longtemps (ça se fait bien dans d'autres domaines).