Deklaracja a definicja.

2

Mamy klasę w pliku test.cpp:

#ifndef _TEST_H_
#define _TEST_H_
class test
{
private: int t;
public: int value()
{
return t;
}
test(int);
};
#endif

W pliku test.cpp:

#include "test.h"
test::test(int a)
{
t=a;
}

Plik pik.h:

#ifndef _PIK_H_
#define _PIK_H_
int pik();
#endif

pik.cpp:

#include <iostream>
#include <test.h>
using namespace std;
int pik()
{
test t(2);
cout<<"pik: "<<t.value()<<endl;
}

main.cpp:

#include <iostream>
#include "test.h"
#include "pik.h"

int main()
{
test t;
cout<<t.value()<<endl;
pik();
}

oraz plik Makefile:

prog: main.o pik.o test.o
    gcc -o [email protected] $^
main.o: main.cpp
    gcc -o [email protected] -c $<
pik.o: pik.cpp
    gcc -o [email protected] -c $<
test.o: test.cpp
    gcc -o [email protected] -c $<

I teraz wykażę jakim błędem jest definiowanie metod podczas deklaracji w plikach nagłówkowych.

  1. Metoda value klasy test wystąpi w plikach obiektowych main.o i pik.o oraz test.o. Jedna metoda jest kompilowana 3 razy. Wydłuża to czas kompilacji.
  2. Plik Makefile jest źle skonstruowany, aby pokazać, że zmiana metody w pliku test.h i ponowna kompilacja prowadzi do błędu. Nie ma zależności do plików nagłówkowych. Nowa metoda będzie tylko w pliku test.o. Linker skorzysta z metody z pliku main.o, dlatego, że jest pierwsza na liście. Będzie to stara metoda.

W wielu projektach widziałem takie krtótkie metody. Teraz pokazałem, że pliki nagłówkowe służą tylko do deklaracji. Definiowanie metod i funkcji w plikach nagłówkowych jest błędem. Zapraszam do polemiki.

1

1) kod który tu wrzuciłeś jest pełen błędów - nie skompiluje się
2) odpalenie tego makefile, który tu dałeś też się nie powiedzie (nie ten kompilator)

Definiowanie metod i funkcji nie jest błędem, błędem jest nieumiejętność kompilacji. Newbie rzeczywiście może mieć z tym problemy, ale ktoś doświadczony, mający codziennie styczność z tymi zagadnieniami nie będzie miał problemów

0

Definiowanie metod i funkcji w plikach nagłówkowych jest błędem. Zapraszam do polemiki.

Z tego co czytałem w symfonii to nie jest błąd. Będą to metody i funkcje inline. Czyli zostaną dopisane tam gdzie są wywołane.

0

Nie czytałem Symfonii. Ale patrząc na to co utworzył kompilator:
test::value()

08048746 <_ZN4test5valueEv>:
 8048746:   55                      push   %ebp
 8048747:   89 e5                   mov    %esp,%ebp
 8048749:   8b 45 08                mov    0x8(%ebp),%eax
 804874c:   8b 00                   mov    (%eax),%eax
 804874e:   83 c0 01                add    $0x1,%eax
 8048751:   5d                      pop    %ebp
 8048752:   c3                      ret

pik()

08048770 <_Z3pikv>:
 8048770:   55                      push   %ebp
 8048771:   89 e5                   mov    %esp,%ebp
 8048773:   53                      push   %ebx
 8048774:   83 ec 24                sub    $0x24,%esp
 8048777:   8d 45 f4                lea    -0xc(%ebp),%eax
 804877a:   89 04 24                mov    %eax,(%esp)
 804877d:   e8 d2 ff ff ff          call   8048754 <_ZN4testC1Ev>
 8048782:   8d 45 f4                lea    -0xc(%ebp),%eax
 8048785:   89 04 24                mov    %eax,(%esp)
 8048788:   e8 b9 ff ff ff          call   8048746 <_ZN4test5valueEv>
...

Funkcje nie są inline.
Ale nie do końca. Funkcje będą inline wtedy gdy zostaną jawnie zadeklarowane inline. Zastanawia mnie jak kompilator radzi sobie z funkcjami inline kompilując jeden plik źródłowy, a funkcja będzie tylko zadelkarowana w pliku nagłówkowym, a zdefiniowana w innym pliku. Może ta odpowiedzialność jest przerzucana na linker. Muszę to sprawdzić.

0

Funkcje będą inline tylko jak kompilator uzna to za stosowne. Słowo kluczowe ma w nosie (albo "bierze je pod uwagę" :P). Tak samo jak definicje metod w plikach nagłówkowych.

0

Co ty opowiadasz ze je ma w nosie ? Przytoczę to co jest napisane w symfonii (mniej więcej). Słowo inline tak jak i register oznacza sugestie dla komplikatora. Jeżeli będzie taka możliwość to to wykona. W dodatku Pan Jerzy wspomniał coś o pętli for, czyli jeżeli inline funkcja ja zawiera nie koniecznie będzie inline.

0

Bumcykowy, TY potrafisz czytac?

0
Bumcykowy napisał(a)

Co ty opowiadasz ze je ma w nosie ? Przytoczę to co jest napisane w symfonii (mniej więcej). Słowo inline tak jak i register oznacza sugestie dla komplikatora. Jeżeli będzie taka możliwość to to wykona. W dodatku Pan Jerzy wspomniał coś o pętli for, czyli jeżeli inline funkcja ja zawiera nie koniecznie będzie inline.

Masz zupełną rację:

Język C++: Pierwsze starcie. Zbigniew koza. str. 76:

Kompilator traktuje słówko inline jako wskazówkę by w miarę możliwości daną funkcję implementować jako otwartą

Czyli kompilator nie ma w nosie tej wskazówki. Gdy można jakąś funkcje zadeklarować jako otwartą, kopilator zrobi to automatycznie. Gdy widzi słówko inline dla funkcji której poprzednio nie brał pod uwagę stara się w miarę możliwości zamienić ją na funkcję otwartą. izi

0

Na płocie było napisane "dupa" a jak przejechałem ręką to sobie wbiłem drzazgę! :P
Nie wierzcie we wszystko co napisali w książkach, tym bardziej jeśli zrobili to 5,10 czy 15 lat temu...
Ale możecie dalej wierzyć w to że słówko jak "register" w jakikolwiek sposób wpłynie na generację kodu wynikowego. Proponuje skompilować sobie program do poziomu asemblera (większość kompilatorów pozwala na przerwanie kompilacji po każdym etapie/ generowanie celów pośrednich) i sprawdźcie czy faktycznie są jakieś różnice ;)

0

Wyrażę tutaj swoją opinię. Co do definicji funkcji w pliku h/hpp sprawa wygląda tak, że trzeba uważnie to wykorzystać. Otóż kod taki:

class Przyklad
{
public:
void setI( int _i ) { i = _i; }
int getI(){ return i; }

int skomplikowanyAlgorytm( int a, int b, int c );

private:
int i;
};

W takim wypadku jest sens by setI() i getI() zdefiniować w pliku h/hpp, ponieważ zmienność tych metod jest niemał nieprawdopodobna, dodatkowo jest spora szansa na to, że będziemy mieli inline.

Metoda skomplikowanyAlgorytm natomiast musi być zadeklarowana w cpp, ponieważ jest duże prawdopodobieństwo grzebania w niej. Co to nam da? Ano to że ograniczymy zasięg ponownej kompilacji w przypadku zmiany w algorytmie.

Moim zdaniem definicja w pliku h/hpp nie jest czymś zabronionym, natomiast trzeba wiedzieć czemu się definiuje w h/hpp. Ponadto gdy robimy template to wtedy mamy tylko plik h/hpp gdzie mamy deklarację i definicję, ponieważ szablonów nie da się rozdzielić na h/hpp i cpp.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0