Chciałbym mieć prywatną stałą statyczną dla klasy (w tym przypadku fabrykę kształtów).
Chciałbym mieć coś w tym rodzaju.
class A {
private:
static const string RECTANGLE = "rectangle";
}
Niestety dostaję różnego rodzaju błędy z kompilatora C ++ (g ++), takie jak:
ISO C ++ zabrania inicjalizacji elementu „RECTANGLE”
niepoprawna inicjalizacja w klasie elementu danych statycznych typu niezintegrowanego „std :: string”
błąd: statyczne ustawienie „RECTANGLE”
Mówi mi to, że tego rodzaju konstrukcja pręta nie jest zgodna ze standardem. Jak masz prywatną literalną stałą (a może publiczną) bez konieczności stosowania dyrektywy #define (Chcę uniknąć brzydoty globalności danych!)
Każda pomoc jest mile widziana.
Odpowiedzi:
Musisz zdefiniować element statyczny poza definicją klasy i podać tam inicjator.
Pierwszy
i wtedy
Składnia, której pierwotnie próbowałeś użyć (inicjator wewnątrz definicji klasy), jest dozwolona tylko w przypadku typów całkowych i wyliczeniowych.
Począwszy od C ++ 17 masz inną opcję, która jest dość podobna do twojej oryginalnej deklaracji: zmienne wbudowane
Nie jest wymagana dodatkowa definicja.
Lub zamiast tego
const
możesz zadeklarowaćconstexpr
w tym wariancie. Jawneinline
nie byłoby już konieczne, ponieważconstexpr
implikujeinline
.źródło
char const*
ma dobroć, że jest inicjowana przed wszystkim inicjalizacji dynamiczna jest wykonywana. Zatem w konstruktorze dowolnego obiektu możesz polegać na tym,RECTANGLE
że już został zainicjowany.W C ++ 11 możesz teraz:
źródło
constexpr
oznaczaconst
zmienną, a nie typ it point. Tj.static constexpr const char* const
Jest taki sam jakstatic constexpr const char*
, ale nie taki sam jakstatic constexpr char*
.Wewnątrz definicji klas można deklarować tylko elementy statyczne. Muszą być zdefiniowane poza klasą. W przypadku stałych całkowania w czasie kompilacji standard stanowi wyjątek, że można „inicjować” elementy. Jednak wciąż nie jest to definicja. Na przykład adres nie działałby bez definicji.
Chciałbym wspomnieć, że nie widzę korzyści z używania std :: string nad const char [] dla stałych . std :: string jest niezły i wymaga dynamicznej inicjalizacji. Więc jeśli napiszesz coś takiego
w obszarze nazw konstruktor foo zostanie uruchomiony tuż przed wykonaniem startów głównych, a ten konstruktor utworzy kopię stałej „hello” w pamięci sterty. Chyba że naprawdę potrzebujesz RECTANGLE, aby był std :: string, możesz równie dobrze napisać
Tam! Bez alokacji sterty, bez kopiowania, bez dynamicznej inicjalizacji.
Pozdrawiam, s.
źródło
To tylko dodatkowe informacje, ale jeśli naprawdę chcesz, aby ciąg znaków w pliku nagłówkowym, spróbuj czegoś takiego:
Chociaż wątpię, żeby to było zalecane.
źródło
W C ++ 17 możesz używać zmiennych wbudowanych :
Zauważ, że różni się to od odpowiedzi w otchłani. 7 : Ta określa rzeczywisty
std::string
obiekt, a nieconst char*
źródło
inline
utworzy wiele duplikatów?To jest ograniczenie. Dlatego w tym przypadku musisz zdefiniować zmienną poza klasą. skieruj odpowiedź z @AndreyT
źródło
Zmienne statyczne klasy można zadeklarować w nagłówku, ale muszą być zdefiniowane w pliku .cpp. Wynika to z faktu, że może istnieć tylko jedna instancja zmiennej statycznej, a kompilator nie może zdecydować, w którym wygenerowanym pliku obiektowym go umieścić, więc musisz podjąć decyzję.
Aby zachować definicję wartości statycznej z deklaracją w C ++ 11, można użyć zagnieżdżonej struktury statycznej. W takim przypadku element statyczny jest strukturą i musi zostać zdefiniowany w pliku .cpp, ale wartości znajdują się w nagłówku.
Zamiast inicjowania poszczególnych elementów cała struktura statyczna jest inicjowana w .cpp:
Dostęp do wartości można uzyskać za pomocą
lub - ponieważ członkowie są prywatni i mają być używane tylko z A - z
Zauważ, że w tym rozwiązaniu nadal występuje problem kolejności inicjalizacji zmiennych statycznych. Gdy wartość statyczna jest używana do inicjalizacji innej zmiennej statycznej, pierwsza może jeszcze nie zostać zainicjowana.
W takim przypadku nagłówki zmiennych statycznych będą zawierać {""} lub {".h", ".hpp"}, w zależności od kolejności inicjowania utworzonej przez linker.
Jak wspomniano w @ abyss.7, można również użyć,
constexpr
jeśli wartość zmiennej można obliczyć w czasie kompilacji. Ale jeśli zadeklarujesz swoje ciągi,static constexpr const char*
a twój program użyjestd::string
inaczej, powstanie narzut, ponieważ nowystd::string
obiekt będzie tworzony za każdym razem, gdy użyjesz takiej stałej:źródło
Obecny standard zezwala tylko na taką inicjalizację dla statycznych typów całek stałych. Musisz więc postępować zgodnie z wyjaśnieniem AndreyT. Będzie to jednak dostępne w następnym standardzie poprzez nową składnię inicjującą członka .
źródło
możliwe po prostu zrób:
lub
źródło
constexpr
ale nie możesz wykonać funkcji statycznejconst
.static const std::string RECTANGLE() const { static const std::string value("rectangle"); return value; }
Możesz albo wybrać
const char*
wyżej wspomniane rozwiązanie, ale jeśli potrzebujesz ciągów przez cały czas, będziesz miał dużo narzutów.Z drugiej strony ciąg statyczny wymaga dynamicznej inicjalizacji, więc jeśli chcesz użyć jego wartości podczas inicjalizacji innej zmiennej globalnej / statycznej, możesz napotkać problem z kolejnością inicjalizacji. Aby tego uniknąć, najtańszą rzeczą jest dostęp do obiektu ciągu statycznego przez moduł pobierający, który sprawdza, czy obiekt został zainicjowany, czy nie.
Pamiętaj, aby używać tylko
A::getS()
. Ponieważ wszelkie wątki mogą być uruchamiane tylkomain()
iA_s_initialized
inicjowane wcześniejmain()
, nie potrzebujesz blokad nawet w środowisku wielowątkowym.A_s_initialized
domyślnie jest 0 (przed dynamiczną inicjalizacją), więc jeśli używaszgetS()
przed inicjalizacją s, bezpiecznie wywołujesz funkcję init.Btw, w odpowiedzi powyżej: „ static const std :: string RECTANGLE () const ”, funkcje statyczne nie mogą być,
const
ponieważ nie mogą zmienić stanu, jeśli jakikolwiek obiekt (mimo to nie ma tego wskaźnika).źródło
Przewiń do 2018 i C ++ 17.
static_assert „działa” tylko w czasie kompilacji
};
Powyżej znajduje się odpowiedni i legalny obywatel C ++. Może łatwo zaangażować się we wszystkie algorytmy std ::, kontenery, narzędzia i tym podobne. Na przykład:
Ciesz się standardowym C ++
źródło
std::string_view
dla stałych tylko wtedy, gdy używaszstring_view
parametrów we wszystkich swoich funkcjach. Jeśli którakolwiek z funkcji używaconst std::string&
parametru, kopia ciągu zostanie utworzona, gdy przekażeszstring_view
stałą przez ten parametr. Jeśli twoje stałe są typu,std::string
kopie nie zostaną utworzone ani dlaconst std::string&
parametrów, ani dlastd::string_view
parametrów.inline
zmienne pojawiły się w C ++ 17 z ich semantyką ODR. Ale string_view to także C ++ 17, więc po prostuconstexpr auto some_str = "compile time"sv;
wykonuje to zadanie (a właściwie to nie jest zmienna, to jestconstexpr
, więcinline
niejawne; jeśli masz zmienną - tj. Nieconstexpr
- toinline auto some_str = "compile time"sv;
zrobi to, chociaż oczywiście zakres przestrzeni nazw zmienna, która jest zasadniczo zmienną globalną, rzadko byłaby dobrym pomysłem).