[C++] Program w 2-óch plikach

Jestem na etapie nauki C++, doszedłem do rozdziału o programach, które mogą składać się z kilku plików z kodem i pliku nagłowkowego.

Napisałem sobie wymyślony przezemnie prosty programik, by wypróbować jak to wszystko działa, ale przy kompilacji pojawiają się błędy.

Oto ten program w poszczególnych plikach:

naglowek.h

extern int liczba;


void wyp();

prog.cpp

#include 

using namespace std;


#include "naglowek.h"

int liczba = 22;

main() {

wyp();

system("pause");

}

prog2.cpp

#include 

using namespace std;


#include "naglowek.h"


void wyp() {


cout << liczba << endl;


}

Ogólnie rzecz biorąc chciałbym, żeby funkcja znajdująca się w pliku prog2.cpp wypisała mi wartość zmiennej globalnej liczba z pliku prog.cpp

Przy kompilacji pliku prog2.cpp wywala mi błąd:

Niby niezdefiniowana jest referencja… z tego co pamiętam referencja służyła do zwracania wartości w funkcji o jakiś argumentach nic nie zwracających…, ale co to ma do tego? Może mi ktoś pomóc jak rozwiązać ten problem?

Jesli prog.cpp jest glownym plikiem “projektu” to powinienes to zrobic tak:

prog.cpp

#include 

#include "prog2.cpp" 

using namespace std; 


int liczba = 22; 

main() { 

wyp(); 

system("pause"); 

}

prog2.cpp

#include 

using namespace std; 


#include "naglowek.h" 


void wyp() { 


cout << liczba << endl; 


}

naglowek.h

extern int liczba; 


void wyp();

Ogółem chodzi o includeowanie odpowiednie, ja też miałem ten problem, robiłem tak jak jest napisane w Symfonii C++ i nie działało:

main.cpp (#include "klasa.h")

klasa.h

klasa.cpp (#include "klasa.h")

musiałem zmienić tak:

main.cpp (#include "klasa.cpp")

klasa.h

klasa.cpp (#include "klasa.h")

I działa, nie wiem czy to dobrze jest, powie ktoś bardziej doświadczony jak to się powinno robić z includeowaniem plików?

Do pliku w dyrektywie #include dodajesz tylko to z czego kozystasz, tzn. pliki ktore zawieraja zmienne/klasy/metody… uzywane w tym pliku…proste. Wrzucanie wszystkiego na raz nie ma sensu.

Rany, jakie herezje!

  1. Nigdy nie załączaj plików cpp, cxx, c. Sugestia nr47 jest błędna.

  2. Staraj się nie używać zmiennych globalnych (int liczba) - to czyste zło, bo nie masz kontroli nad tym kto i kiedy zmienił jej wartość (oraz dlaczego). W programie jednowątkowym to rzadki problem i potencjalnie łatwy do wyłapania błąd. W programie wielowątkowym to prawdziwa zmora.

  3. Dużo zależy od tego jak kompilujesz. Możesz opisać proces?

  4. Poprawiony (ale nie poprawny) kod:

naglowek.h

#ifndef __NAGLOWEK_H

#define __NAGLOWEK_H

extern int liczba;


extern void wyp();

#endif /* __NAGLOWEK_H */

Tutaj kilka wyjaśnień. - extern jest puste w C++ (a pracujesz z C++, skoro masz pliki cpp, prawda?); oznacza to, że słowo to jest zbędne przy eksportowanych zmiennych i funkcjach i można je pominąć - jeśli plik nagłówkowy pojawia się w więcej niż jednym pliku .c/.cpp/.cxx/… to zawartość pliku powinna być ujęta w widoczną wyżej parę ifndef/define/endif - nazwa użyta w ifndef/define/endif musi być unikatowa (nie może kolidować z żadną inną Twoją ani z żadną z innych plików nagłówkowych) A teraz jeszcze o “sztuczce” z ifndef. Skoro extern jest opcjonalne, to mamy w rzeczywistości definicję: int liczba; Nie możesz mieć kilku globalnych zmiennych o tej samej nazwie, prawda? Jeśli jeden z plików .cpp poprzez załączenie pliku .h zdefiniował ją globalnie, zostanie utworzona definicja __NAGLOWEK_H, która spowoduje, że załączenie drugi raz tej samej definicji (ifndef) nie będzie możliwe. Drobiazg: zależnie od kompilatora i jego parametrów może być jeszcze wymagane użycie: #ifdef __cplusplus extern “C” { #endif Nie piszesz jaki kompilator, więc sam jesteś sobie winien. :stuck_out_tongue: prog.cpp

#include 

#include "naglowek.h"


using namespace std;


main() {

    liczba = 22;

    wyp();

    system("pause");

}
  • pliki nagówkowe trzymaj razem; dzielone <> pierwsze a własne “” za nimi (są od tej reguły wyjątki) - namespace nie będzie działało w niektórych kompilatorach Borlanda prog2.cpp

    #include

    #include “naglowek.h”

    using namespace std;

    int liczba;

    void wyp() {

    cout << liczba << endl;

    }

  • popełniłem tak jak Ty grzech umieszczenia tutaj liczby, z tym że Twój plik nagłówkowy definiował po jednej rzeczy z dwu różnych plików .c - powinieneś mieć jeden .h na jeden .cpp, chyba że ze względu na faktoryzację i czystość kodu masz kilka plików .c opisujących jedną klasę. Poprawnie funkcja wyp powinna przyjmować parametr. Generalnie powinno to jednak wygladać tak: funkcje.h

    #ifndef __FUNKCJE_H

    #define __FUNKCJE_H

    void wyp(int liczba);

    #endif /* __FUNKCJE_H */

main.cpp

#include 

#include "funkcje.h"


void main(void) {

    in liczba = 22;

    wyp(liczba);

    system("pause");

}

funkcje.cpp

#include 

#include "naglowek.h"


using namespace std;


void wyp(int liczba) {

    cout << liczba << endl;

}
  • nie używasz zmiennej globalnej

  • nazwy plików cpp i h są zgodne

Jeśli chcesz poćwiczyć zło, którym są zmienne globalne - mogę podać Ci przykład programu, gdzie jest to rzeczywiście ułatwieniem a nie utrudnieniem.

Ryan więc jak powinienem zrobić?

Mam 3 pliki:

main.cpp - główny plik programu

klasa.h - plik nagłówkowy z klasą

klasa.cpp - plik z funkcjami klasy z pliku klasa.h

Kiedy mam taką konfigurację:

main.cpp (#include "klasa.h")

klasa.h

klasa.cpp (#include "klasa.h")

Dostaję alerty undefined reference to (i tu nazwy funkcji z pliku klasa.cpp). Po zmianie, którą określiłeś jako błąd, program się linkuje i działa. Tak więc jak to powinno być?

A zawartość plików skąd mam wziąć? Nie ma jednej odpowiedzi, która pasuje do każdego przypadku. C++ jest trochę bardziej złożone niż kreślenie trójkątów palcem na piasku i są konstrukcje, które wymagają złamania dobrych zasad budowania kodu. Załóż temat, wklej swój kod, odpowiem na pytanie. :slight_smile:

nr47

Na przyszłość nie podczepiaj się pod inny temat.JNJN