Chcę mieć klasę z prywatnym statycznym składnikiem danych (wektorem zawierającym wszystkie znaki az). W Javie lub C # mogę po prostu stworzyć „statyczny konstruktor”, który będzie działał przed utworzeniem jakichkolwiek instancji klasy, i ustawiam statyczne składowe danych klasy. Jest uruchamiany tylko raz (ponieważ zmienne są tylko do odczytu i muszą być ustawione tylko raz), a ponieważ jest to funkcja klasy, ma dostęp do swoich prywatnych członków. Mógłbym dodać kod w konstruktorze, który sprawdza, czy wektor jest zainicjowany, i inicjuje go, jeśli tak nie jest, ale wprowadza to wiele niezbędnych kontroli i nie wydaje się optymalnym rozwiązaniem problemu.
Przychodzi mi do głowy myśl, że skoro zmienne będą tylko do odczytu, mogą być po prostu publicznymi stałymi statycznymi, więc mogę ustawić je raz poza klasą, ale znowu wygląda to na brzydki hack.
Czy można mieć prywatne statyczne elementy członkowskie w klasie, jeśli nie chcę ich inicjować w konstruktorze instancji?
źródło
Odpowiedzi:
Aby uzyskać odpowiednik konstruktora statycznego, musisz napisać oddzielną zwykłą klasę do przechowywania danych statycznych, a następnie utworzyć statyczną instancję tej zwykłej klasy.
źródło
friend
ma to duży sens, aby klasaElsewhere
mogła łatwo uzyskać dostęp doStaticStuff
wewnętrznych elementów (bez przerywania hermetyzacji w żaden niebezpieczny sposób, dodam).Cóż, możesz mieć
Nie zapomnij (w .cpp) o tym:
Program będzie nadal łączył się bez drugiej linii, ale inicjator nie zostanie wykonany.
źródło
MyClass::a.push_back(i)
zamiast tegoa.push_back(i)
?_initializer
jest podobiektemMyClass
. Podobiekty są inicjowane w następującej kolejności: podobiekty wirtualnej klasy bazowej, w kolejności od początku do końca, od lewej do prawej (ale inicjalizacja każdego odrębnego podobiektu tylko raz); następnie zwykłe podobiekty klasy bazowej, w kolejności od lewej do prawej; następnie podobiekty składowe w kolejności deklaracji. Dlatego można bezpiecznie używać strategii EFraim, pod warunkiem, że kod_initialiser
odnosi się tylko do członków zadeklarowanych przed nim.Rozwiązanie C ++ 11
Od C ++ 11 możesz po prostu użyć wyrażeń lambda do zainicjowania statycznych składowych klas. Działa to nawet wtedy, gdy trzeba narzucić kolejność konstrukcji między różnymi statycznymi elementami lub jeśli masz statyczne elementy, które są
const
.Plik nagłówkowy:
Plik źródłowy:
źródło
try catch
Jeśli mogą zostać zgłoszone wyjątki, należy zawinąć logikę inicjatora w blok.W pliku .h:
W pliku .cpp:
źródło
Oto inne podejście, podobne do Daniela Earwickera, wykorzystujące również sugestię klasy przyjaciela Konrada Rudolpha. Tutaj używamy wewnętrznej klasy użytkowej znajomego prywatnego, aby zainicjować statyczne elementy składowe Twojej głównej klasy. Na przykład:
Plik nagłówkowy:
Plik wdrożeniowy:
To podejście ma tę zaletę, że całkowicie ukrywa klasę Initializer przed światem zewnętrznym, zachowując wszystko zawarte w klasie, która ma zostać zainicjowana.
źródło
ToBeInitialized::Initializer::Initializer()
zostanie wywołany, więc musisz dodaćToBeInitialized::Initializer ToBeInitialized::initializer;
do pliku implementacji. Wziąłem kilka rzeczy z Twojego pomysłu oraz z pomysłu EFraima i działa dokładnie tak, jak tego potrzebuję i wygląda na czysty. Dzięki.Test::StaticTest()
jest wywoływana dokładnie raz podczas globalnej inicjalizacji statycznej.Wzywający musi tylko dodać jedną linię do funkcji, która ma być ich konstruktorem statycznym.
static_constructor<&Test::StaticTest>::c;
wymusza inicjalizacjęc
podczas globalnej inicjalizacji statycznej.źródło
Nie potrzebujesz
init()
funkcji,std::vector
można ją utworzyć z zakresu:Należy jednak pamiętać, że statyka typu klasy powoduje problemy w bibliotekach, dlatego należy ich tam unikać.
Aktualizacja C ++ 11
Począwszy od C ++ 11, możesz to zrobić zamiast tego:
Jest semantycznie równoważne z rozwiązaniem C ++ 98 w oryginalnej odpowiedzi, ale nie można użyć literału ciągu po prawej stronie, więc nie jest całkowicie lepszy. Jednakże, jeśli masz wektor innego rodzaju niż
char
,wchar_t
,char16_t
lubchar32_t
(tablice, z których może być zapisany jako napisowych), wersja C ++ 11 będzie bezwzględnie usunąć kod szablonowe bez wprowadzania innej składni, w porównaniu do C ++ 98 wersja.źródło
Pojęcie konstruktorów statycznych zostało wprowadzone w Javie po zapoznaniu się z problemami w C ++. Nie mamy więc bezpośredniego odpowiednika.
Najlepszym rozwiązaniem jest użycie typów POD, które można jawnie zainicjować.
Lub nadaj statycznym elementom członkowskim określony typ, który ma własny konstruktor, który zainicjuje go poprawnie.
źródło
Próbując skompilować i użyć klasy
Elsewhere
(z odpowiedzi Earwickera ) otrzymuję:Wydaje się, że nie jest możliwe zainicjowanie statycznych atrybutów typów innych niż całkowite bez umieszczenia kodu poza definicją klasy (CPP).
Aby dokonać tej kompilacji, możesz zamiast tego użyć „ metody statycznej ze statyczną zmienną lokalną wewnątrz ”. Coś takiego:
Możesz również przekazać argumenty do konstruktora lub zainicjować go określonymi wartościami, jest bardzo elastyczny, wydajny i łatwy do zaimplementowania ... jedyną rzeczą jest to, że masz metodę statyczną zawierającą zmienną statyczną, a nie atrybut statyczny ... składnia zmienia się nieco, ale nadal jest przydatna. Mam nadzieję, że komuś się to przyda,
Hugo González Castro.
źródło
Myślę, że prostym rozwiązaniem będzie:
źródło
Właśnie rozwiązałem tę samą sztuczkę. Musiałem określić definicję pojedynczego statycznego elementu członkowskiego dla Singletona. Ale komplikuj sprawę - zdecydowałem, że nie chcę wywoływać ctora RandClass (), chyba że go użyję ... dlatego nie chciałem inicjalizować singletona globalnie w swoim kodzie. Dodałem też prosty interfejs w moim przypadku.
Oto ostateczny kod:
Uprościłem kod i użyłem funkcji rand () i jej pojedynczego ziarna initialzer srand ()
źródło
Oto mój wariant rozwiązania EFraim; różnica polega na tym, że dzięki niejawnej instancji szablonu konstruktor statyczny jest wywoływany tylko wtedy, gdy tworzone są instancje klasy i nie
.cpp
jest potrzebna żadna definicja w pliku (dzięki magii tworzenia instancji szablonu).W
.h
pliku masz:W
.cpp
pliku możesz mieć:Zauważ, że
MyClass::a
jest inicjowane tylko wtedy, gdy istnieje linia [1], ponieważ wywołuje (i wymaga utworzenia instancji) konstruktora, który następnie wymaga instancji_initializer
.źródło
Oto inna metoda, w której wektor jest prywatny dla pliku zawierającego implementację przy użyciu anonimowej przestrzeni nazw. Jest to przydatne w przypadku takich rzeczy, jak tabele wyszukiwania, które są prywatne dla implementacji:
źródło
I
ii
coś bardziej niejasnego, aby nie przypadkowo użyć ich gdzieś niżej w pliku.Z pewnością nie musi być tak skomplikowane, jak obecnie akceptowana odpowiedź (autorstwa Daniela Earwickera). Klasa jest zbędna. W tym przypadku nie ma potrzeby wojny językowej.
plik .hpp:
plik .cpp:
źródło
Oferty GCC
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
Oznacz metodę statyczną tym atrybutem, a będzie ona działać przy ładowaniu modułu, przed funkcją main ().
źródło
Definiujesz statyczne zmienne składowe podobnie do sposobu definiowania metod składowych.
foo.h
foo.cpp
źródło
Aby zainicjować zmienną statyczną, wystarczy zrobić to wewnątrz pliku źródłowego. Na przykład:
źródło
Co powiesz na utworzenie szablonu naśladującego zachowanie języka C #.
źródło
W prostych przypadkach, takich jak tutaj, zmienna statyczna opakowana wewnątrz statycznej funkcji składowej jest prawie tak dobra. Jest to proste i zazwyczaj zostanie zoptymalizowane przez kompilatory. Nie rozwiązuje to jednak problemu kolejności inicjalizacji dla złożonych obiektów.
źródło
Czy to jest rozwiązanie?
źródło
Konstruktor statyczny można emulować przy użyciu klasy zaprzyjaźnionej lub klasy zagnieżdżonej, jak poniżej.
Wynik:
źródło
new
tablica znaków służy tylko do natychmiastowego wycieku wskaźnika i nadpisania go !?Wow, nie mogę uwierzyć, że nikt nie wspomniał o najbardziej oczywistej odpowiedzi, która najbardziej naśladuje zachowanie statycznego konstruktora C #, tj. Nie jest wywoływana, dopóki nie zostanie utworzony pierwszy obiekt tego typu.
std::call_once()
jest dostępny w C ++ 11; jeśli nie możesz tego użyć, możesz to zrobić za pomocą statycznej zmiennej typu boolean oraz operacji atomowej typu „porównaj i zamień”. Sprawdź w swoim konstruktorze, czy możesz atomowo zmienić flagę statyczną klasy zfalse
natrue
, a jeśli tak, możesz uruchomić kod konstrukcji statycznej.Aby uzyskać dodatkowe punkty, utwórz flagę trójstronną zamiast wartości logicznej, tj. Nie uruchomiono, uruchomiono i zakończono uruchamianie. Następnie wszystkie inne instancje tej klasy mogą się blokować, dopóki instancja, na której działa konstruktor statyczny, nie zakończy się (tj. Wystawi ochronę pamięci, a następnie ustaw stan na „gotowe do działania”). Twój spin-lock powinien wykonywać instrukcję "pauza" procesora, podwajać czas oczekiwania aż do progu itd. - całkiem standardowa technika blokowania obrotów.
W przypadku braku C ++ 11 to powinno Ci zacząć.
Oto pseudokod, który Cię poprowadzi. Umieść to w definicji swojej klasy:
A to w twoim konstruktorze:
źródło