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?
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.
Nigdy nie załączaj plików cpp, cxx, c. Sugestia nr47 jest błędna.
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.
Dużo zależy od tego jak kompilujesz. Możesz opisać proces?
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. 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.
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.