[C++] Inicjalizacja zmiennych statycznych 5998 14

O temacie

Autor Wonski

Zaczęty 30.11.2015 roku

Wyświetleń 5998

Odpowiedzi 14

Wonski

Wonski

Gry (themodders@telegram)
radio engineer
posty256
Propsy91
ProfesjaProgramista
  • Gry (themodders@telegram)
  • radio engineer

Wonski
Gry (themodders@telegram)

[C++] Inicjalizacja zmiennych statycznych
2015-11-30, 17:50(Ostatnia zmiana: 2015-11-30, 18:42)
Witam,
Wam klasę Connect:
class Connect final :protected Connectdata
{
//zmienne statyczne
static int unique_connect;
static int total_connect;
public:


//konstruktor z wartościami domyślnymi
Connect(int begin_value = 0) : Connectdata(begin_value)
{
number_connect = unique_connect++;
total_connect++;
};

// konstruktor z wartościami ustawianymi
Connect(int output, int entrace, int weight) : Connectdata(output, entrace, weight)
{
number_connect = unique_connect++;
total_connect++;
};

// konstruktor kopiujący
Connect(const Connect &connect) :Connectdata(connect)
{
number_connect = unique_connect++;
total_connect++;
};

//destruktor
~Connect()
       {
               total_connect--;
       };

//interfejs


// funkcje zaprzyjaźnione


};

Problem jakiego nie mogę rozwiązać, dotyczy eleganckiej inicjalizacji zmiennych statycznych podczas startu programu.
Mam kilka klas i każda ma po kilka zmiennych statycznych i zapis:

int Vertex::unique_vertex = 1;
int Vertex::total_vertex = 1;

int Connect::unique_connect = 1;
int Connect::total_connect = 1;
int main()
{
// ..... program
}

jest cholernie niewygodny i nieelegancki.
Chciałem to zrobić za pomocą metody statycznej

         static void initialize()
{
unique_connect = 1;
total_connect = 1;
}

również nie chce działać.
Funkcje zaprzyjaźnione również nie dają oczekiwanego rezultatu
friend void initialize();

//........

void initialize()
{
       int Connect::total_connect = 1;
}

Kombinowanie ze słowem kluczowym extern również wywołuje błędy kompilacji.
Na pewno jest na to jakiś banalny i elegancki sposób, bo nie uśmiecha mi się przed funkcją main znacjonalizować kilkanaście zmiennych.
Pozdrawiam

EDIT:
Kiedyś miałem problem z odtwarzaniem dźwięku w aplikacji, to
@Adanos  poradził pokombinować z warunkiem if i typem bool. Zastosowałem to samo tutaj, tylko że, w ciele konstruktora, ale też nie działa.

EDIT2:
Chyba jednak będę musiał zrezygnować ze zmiennych statycznych i zastąpić je "normalnymi". Dzięki temu będę mógł użyć tego triku z konstruktorem.

EDIT3:
Nope. Jednak nie zadziała. Zmienna bool musiałaby być statyczna, czyli... musiałbym ją zainicjować :ayfkm:
private:
int unique_connect;
int total_connect;
bool flag = true;

Connect(int begin_value = 0) : Connectdata(begin_value)
{
if (flag)
{
unique_connect = 1;
total_connect = 1;
flag = false;
}
number_connect = unique_connect++;
total_connect++;
};

Chociaż plus, jest taki, że mogę zainicjować wszystkie zmienne startowe wszystkich klas w jednej funkcji, którą mogę wywołać przy starcie  aplikacji..

EDIT 4:
Jednak to musi być rozwiązanie na zmiennych statycznych.
Jeśli ktoś ma pomysł jak to zrobić to chętnie poczytam.
 

Adanos

Adanos

Administrator
Szara eminencja
posty5204
Propsy3870
ProfesjaProgramista
  • Administrator
  • Szara eminencja
Czemu przed funkcją main chcesz inicjalizować zmienne statyczne? Zrób to w pliku źródłowym klasy. W pliku nagłówkowym deklarujesz zmienne statyczne.

Wonski

Wonski

Gry (themodders@telegram)
radio engineer
posty256
Propsy91
ProfesjaProgramista
  • Gry (themodders@telegram)
  • radio engineer

Wonski
Gry (themodders@telegram)

[C++] Inicjalizacja zmiennych statycznych
#2 2015-11-30, 19:39(Ostatnia zmiana: 2015-11-30, 20:11)
Wywala:
1>core_struct.obj : error LNK2005: "public: static int Connect::total_connect" (?total_connect@Connect@@2HA) already defined in connect.obj
1>core_struct.obj : error LNK2005: "public: static int Connect::unique_connect" (?unique_connect@Connect@@2HA) already defined in connect.obj

w pliku core_struct.cpp testuję działanie całego programu.
Pracuję w visual studio 2015

A same zmienne zadeklarowałem tak jak mówiłeś w pliku nagłówkowym klasy, po ciele klasy:
int Connect::unique_connect =1;
int Connect::total_connect =1;

EDIT
Wywaliłem te zmienne do pliku .cpp klasy w wszystko działa ok.
To zapewne jakieś błędy związane z projektem, ponieważ gdy utworzyłem nowy projekt z przykładową klasą to Twój sposób z deklaracją tych zmiennych w pliku nagłówkowym klasy działa.

Ehhh
Jednak to było takie proste  :D
Dzięki za pomoc.
 

Adanos

Adanos

Administrator
Szara eminencja
posty5204
Propsy3870
ProfesjaProgramista
  • Administrator
  • Szara eminencja
A same zmienne zadeklarowałem tak jak mówiłeś w pliku nagłówkowym klasy, po ciele klasy:
int Connect::unique_connect =1;
int Connect::total_connect =1;
To jest inicjalizacja, którą należy umieścić w pliku źródłowym. Deklaracja tak wygląda w pliku nagłówkowym:
Cytuj
class Connect
{
private:
    static int unique_connect;
    static int total_connect;
};

Chociaż może już teraz tak masz. :D

oskardon

oskardon

Użytkownicy
posty91
Propsy38
ProfesjaGracz
  • Użytkownicy
To ja dodam że wybór pliku to tylko konwencja (uzasadniona), dla kompilatora liczy się to żeby inicjalizacja była po ciele klasy.
 
Life is brutal and full of zasadzkas.

Adanos

Adanos

Administrator
Szara eminencja
posty5204
Propsy3870
ProfesjaProgramista
  • Administrator
  • Szara eminencja
Wydaje mi się, że autor tematu pisze wszystko w jednym pliku (albo nie do końca wie, co gdzie ma być), a jak wiadomo w C++ trzeba podzielić pliki na źródłowe i nagłówkowe, bo ma to znaczenie dla kompilatora. :D

oskardon

oskardon

Użytkownicy
posty91
Propsy38
ProfesjaGracz
  • Użytkownicy
Nie, właśnie nie trzeba - powinno się.

Można mieć wszystko w jednym pliku .cpp i skompiluje się tak samo. Jak robiłeś hello world, to trzeba było to dzielić na implementację i nagłówek? ;p

Przy kompilacji pliku, najpierw uruchamiany jest preprocesor. On zajmuje się dyrektywami zaczynającymi się od "#" - jak define i include. W przypadku dyrektyw #include, wkleja zawartość pliku na który wskazują w ich miejsce. W ten sposób na podstawie każdego pliku .cpp tworzony jest tymczasowy byt nazywany jednostką kompilacji (ang. compilation unit) i przekazywany do kompilatora. Odpowiedni parametr gcc'a, msvc, czy czego tam używasz, może ci zapisać ten byt do pliku na dysku w celu przejrzenia go.

Kompilator może kompilować wiele jednostek kompilacji równolegle, do tego kiedy coś zmienisz w którejś z nich, musi przekompilować tylko tą jedną, a pozostałe może odczytać z już skompilowanej formy. W ten sposób na podstawie każdej jednostki kompilacji powstaje plik obiektu (zwykle .o).

Następnie do akcji wkracza linker, który łączy wszystkie pliki obiektów sprawdzając przy tym czy zawarte w nich deklaracje się ze sobą zgadzają. Te deklaracje zwykle umieszcza się w plikach nagłówkowych (.h) i dzięki temu można je zaincludować w kilku jednostkach kompilacji, właśnie żeby była między nimi wspomniana zgodność. Linker na koniec produkuje plik wykonywalny (pod Windowsem .exe).
 
Life is brutal and full of zasadzkas.

Adanos

Adanos

Administrator
Szara eminencja
posty5204
Propsy3870
ProfesjaProgramista
  • Administrator
  • Szara eminencja
Skompilować się skompiluje, ale co z czasem kompilacji? :D Oto głównie chodzi, żebyś nie kompilował za każdym razem wszystkich plików źródłowych, tylko ten który został zmieniony. Pliki nagłówkowe są dołączane i nie kompilowane, natomiast pliki źródłowe są kompilowane i nie dołączane. Gdyby ktoś zrobił coś takiego:
#include "a.cpp"
#include "b.cpp"
#include "c.cpp"
#include "d.cpp"
#include "e.cpp"
to wtedy dodatkowo 5 klas (a, b, c, d, e) by się kompilowało, nawet jeśli nic nie zostało zmienione!
#include "a.hpp"
#include "b.hpp"
#include "c.hpp"
#include "d.hpp"
#include "e.hpp"
Tu natomiast żadnych dodatkowych klas się nie kompiluje.

On zajmuje się dyrektywami zaczynającymi się od "#" - jak define i include. W przypadku dyrektyw #include, wkleja zawartość pliku na który wskazują w ich miejsce.
Wkleja zawartość pliku jeśli jest plikiem nagłówkowym. Jeśli jest plikiem źródłowym to kompiluje a nie wkleja.

oskardon

oskardon

Użytkownicy
posty91
Propsy38
ProfesjaGracz
  • Użytkownicy
Czas kompilacji będzie gorszy, dlatego powinno się (ale nie trzeba) wydzielać deklaracje do plików .h i to je includować w innych plikach .cpp.
Jak pisałem dwa posty temu, jest to uzasadniona konwencja (ale nie obowiązkowa reguła). 

BTW, #include zawsze wkleja, nieważne jakie jest rozszerzenie podanego pliku. Dyrektywami zajmuje się preprocesor. Kompiluje dopiero kompilator, plik który już tych dyrektyw nie ma a zamiast tego ma kompletną jednostkę kompilacji. Zwykle są łączone w jedną aplikację (razem z linkerem), ale to osobne fazy i można np odpalać jedną z nich zostawiając inne na później.
 
Life is brutal and full of zasadzkas.

Wonski

Wonski

Gry (themodders@telegram)
radio engineer
posty256
Propsy91
ProfesjaProgramista
  • Gry (themodders@telegram)
  • radio engineer

Wonski
Gry (themodders@telegram)

[C++] Inicjalizacja zmiennych statycznych
#9 2015-12-02, 17:15(Ostatnia zmiana: 2015-12-02, 17:27)
@Adanos
Konstruktory piszę w pliku nagłówkowym a ciała innych metod w pliku cpp. Tak mi jest wygodniej.
No i jak "szkicuje" metodę to również robię to w pliku .h/.hpp a potem copypast do .cpp
 

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
ja wszystkie definicje poza przeciążaniem operatorów robię w .cpp. Ostatnio zacząłem się zastanawiać, czy nie przenieść definicji prostych getterów i setterów do nagłówka.
 
Popisuje się ciągle menda jedna...

Wonski

Wonski

Gry (themodders@telegram)
radio engineer
posty256
Propsy91
ProfesjaProgramista
  • Gry (themodders@telegram)
  • radio engineer
Wydaje mi się, że tu chodzi o estetykę, tj. plik .h to spis treści, przejrzysty z krótkim komentarzem do metod. Tak więc, przerzucanie ciał metod do piku .h to psucie tej estetyki, nawet jeśli są to właśnie gettery i settery co mają po jednej linii kodu.

 

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
niby tak, ale wkurzają mnie juz pliki cpp rozepchane przez gettery i settery.
 
Popisuje się ciągle menda jedna...

Wonski

Wonski

Gry (themodders@telegram)
radio engineer
posty256
Propsy91
ProfesjaProgramista
  • Gry (themodders@telegram)
  • radio engineer
No to wywal je do osobnego pliku i po problemie. Albo jak nie chcesz tworzyć nowych plików to dodaj sekcję na końcu plików, oddziel widocznym komentarzem i to będzie sekcja tylko dla nich. No bo chyba stosujesz jakiś porządek w pliku cpp?
 

mgr Fartuess

mgr Fartuess

Użytkownicy
Kiedyś to były czasy!
posty1485
Propsy890
ProfesjaProgramista
  • Użytkownicy
  • Kiedyś to były czasy!
Tylko tyle, że metody publiczne idą na górę, potem chronione i na końcu prywatne. Trochę się powstrzymuję ze zbytnim wymyślaniem własnych konwencji i raczej szukam takich w miarę popularnych. Porządku bardziej pilnuję w headerach.
 
Popisuje się ciągle menda jedna...


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry