Czy powinienem używać #define, enum lub const?

W projekcie C++, nad którym pracuję, mam flagę rodzaj wartości, która może mieć cztery wartości. Te cztery flagi można łączyć. Flagi opisują rekordy w bazie danych i mogą być:

  • nowy rekord
  • usunięty rekord
  • zmodyfikowany rekord
  • istniejący rekord

Teraz, dla każdego rekordu chcę zachować ten atrybut, więc mogę użyć enum:

enum { xNew, xDeleted, xModified, xExisting }

Jednak w innych miejscach kodu muszę wybrać, które rekordy mają być jest to jeden z najbardziej rozpoznawalnych i najbardziej rozpoznawalnych w świecie gier komputerowych.]}

showRecords(xNew | xDeleted);

Więc, wygląda na to, że mam trzy możliwe appoach:

#define X_NEW      0x01
#define X_DELETED  0x02
#define X_MODIFIED 0x04
#define X_EXISTING 0x08

Lub

typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;

Lub

namespace RecordType {
    static const uint8 xNew = 1;
    static const uint8 xDeleted = 2;
    static const uint8 xModified = 4;
    static const uint8 xExisting = 8;
}

Wymagania dotyczące przestrzeni są ważne (bajt vs int), ale nie kluczowe. Z definicjami tracę bezpieczeństwo typu, A z enum tracę trochę miejsca (liczby całkowite) i prawdopodobnie muszę rzucać, gdy chcę wykonać bitową operację. Z const myślę, że również tracę bezpieczeństwo typu, ponieważ losowy uint8 może dostać się do przez pomyłkę.

Jest jakiś inny sposób czyszczenia?

Jeśli nie, to czego byś użył i dlaczego?

P. S. reszta kodu jest raczej czystym nowoczesnym C++ bez #defines, a ja użyłem przestrzeni nazw i szablonów w kilku spacjach, więc te też nie są wykluczone.

Author: Thom Wiggers, 2008-09-22

15 answers

Połącz strategie, aby zmniejszyć wady jednego podejścia. Pracuję w systemach wbudowanych, więc poniższe rozwiązanie opiera się na fakcie, że operatory integer i bitwise są szybkie, mało pamięci i niskie zużycie flash.

Umieść enum w przestrzeni nazw, aby zapobiec zanieczyszczeniu globalnej przestrzeni nazw przez stałe.

namespace RecordType {

Enum deklaruje i definiuje typowany czas kompilacji. Zawsze używaj sprawdzania typu czasu kompilacji, aby upewnić się, że argumenty i zmienne są biorąc pod uwagę prawidłowy typ. Nie ma potrzeby stosowania typedef w C++.

enum TRecordType { xNew = 1, xDeleted = 2, xModified = 4, xExisting = 8,

Utwórz inny członek dla nieprawidłowego stanu. Może to być przydatne jako kod błędu; na przykład, gdy chcesz zwrócić stan, ale operacja We / Wy nie powiedzie się. Jest to również przydatne do debugowania; użyj go w listach inicjalizacyjnych i destruktorach, aby wiedzieć, czy wartość zmiennej ma być użyta.

xInvalid = 16 };

Weź pod uwagę, że masz dwa cele dla tego typu. Aby śledzić aktualny stan rekordu i utworzyć maskę aby wybrać rekordy w niektórych stanach. Utwórz funkcję inline, aby sprawdzić, czy wartość tego typu jest prawidłowa dla Twojego celu; jako znacznik stanu vs Maska stanu. Spowoduje to wychwycenie błędów, ponieważ typedef jest tylko int, a wartość taka jak 0xDEADBEEF może znajdować się w zmiennej poprzez niezaliczone lub błędnie określone zmienne.

inline bool IsValidState( TRecordType v) {
    switch(v) { case xNew: case xDeleted: case xModified: case xExisting: return true; }
    return false;
}

 inline bool IsValidMask( TRecordType v) {
    return v >= xNew  && v < xInvalid ;
}

Dodaj dyrektywę using, Jeśli chcesz często używać tego typu.

using RecordType ::TRecordType ;

Funkcje sprawdzania wartości są przydatne w twierdzeniach do przechwytywania złych wartości zaraz po ich użyciu. Im szybciej złapiesz pluskwę podczas biegania, tym mniejsze szkody może on wyrządzić.

Oto kilka przykładów, aby to wszystko połączyć.

void showRecords(TRecordType mask) {
    assert(RecordType::IsValidMask(mask));
    // do stuff;
}

void wombleRecord(TRecord rec, TRecordType state) {
    assert(RecordType::IsValidState(state));
    if (RecordType ::xNew) {
    // ...
} in runtime

TRecordType updateRecord(TRecord rec, TRecordType newstate) {
    assert(RecordType::IsValidState(newstate));
    //...
    if (! access_was_successful) return RecordType ::xInvalid;
    return newstate;
}

Jedynym sposobem zapewnienia prawidłowego bezpieczeństwa wartości jest użycie dedykowanej klasy z przeciążeniami operatora, która jest pozostawiona jako ćwiczenie dla innego czytnika.

 82
Author: mat_geek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-18 16:54:46

Zapomnij o definicjach

Zanieczyszczą Twój kod.

Bitfields?

struct RecordFlag {
    unsigned isnew:1, isdeleted:1, ismodified:1, isexisting:1;
};

Nigdy nie używaj tego . Jesteś bardziej zainteresowany szybkością niż oszczędnością 4 int. Korzystanie z pól bitowych jest w rzeczywistości wolniejsze niż dostęp do jakiegokolwiek innego typu.

Jednak elementy bitowe w strukturach mają praktyczne wady. Po pierwsze, kolejność bitów w pamięci różni się w zależności od kompilatora. Ponadto wiele popularnych kompilatorów generuje nieefektywny kod do odczytu istnieją potencjalnie poważne problemy bezpieczeństwa wątku dotyczące pól bitowych (szczególnie w systemach wieloprocesorowych) ze względu na fakt, że większość maszyn nie może manipulować dowolnymi zestawami bitów w pamięci, ale zamiast tego musi ładować i przechowywać całe słowa. na przykład, poniższe nie będą bezpieczne dla wątku, pomimo użycia mutex

Źródło: http://en.wikipedia.org/wiki/Bit_field :

I jeśli potrzebujesz więcej powodów, aby nie używaj bitfieldów, być może Raymond Chen przekona cię w swoim The Old New Thing Post: analiza kosztów i korzyści bitfieldów dla zbioru booleanów w http://blogs.msdn.com/oldnewthing/archive/2008/11/26/9143050.aspx

Const int?

namespace RecordType {
    static const uint8 xNew = 1;
    static const uint8 xDeleted = 2;
    static const uint8 xModified = 4;
    static const uint8 xExisting = 8;
}

Umieszczenie ich w przestrzeni nazw jest fajne. Jeśli są zadeklarowane w CPP lub pliku nagłówkowym, ich wartości zostaną zainlinowane. Będziesz mógł użyć switch na tych wartościach, ale to nieznacznie zwiększy sprzężenie.

Ach, tak: Usuń słowo kluczowe statyczne. static jest przestarzały w C++, gdy jest używany tak jak ty, a jeśli uint8 jest typem buildina, nie będziesz potrzebował tego, aby zadeklarować to w nagłówku dołączonym przez wiele źródeł tego samego modułu. W końcu kod powinien brzmieć:

namespace RecordType {
    const uint8 xNew = 1;
    const uint8 xDeleted = 2;
    const uint8 xModified = 4;
    const uint8 xExisting = 8;
}

Problem tego podejścia polega na tym, że Twój kod zna wartość Twoich stałych, co nieznacznie zwiększa sprzężenie.

Enum

To samo co const int, z nieco mocniejszym pisaniem.

typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;

Nadal zanieczyszczają globalną przestrzeń nazw. Przy okazji... Usuń typedef. Pracujesz w C++. Te typy enum i struktur zanieczyszczają kod bardziej niż cokolwiek innego.

Wynik jest taki:

enum RecordType { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } ;

void doSomething(RecordType p_eMyEnum)
{
   if(p_eMyEnum == xNew)
   {
       // etc.
   }
}

Jak widzisz, Twoje enum zanieczyszcza globalną przestrzeń nazw. Jeśli umieścisz to enum w przestrzeni nazw, będziesz miał coś w stylu:

namespace RecordType {
   enum Value { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } ;
}

void doSomething(RecordType::Value p_eMyEnum)
{
   if(p_eMyEnum == RecordType::xNew)
   {
       // etc.
   }
}

Extern const int ?

Jeśli jeśli chcesz zmniejszyć sprzężenie (tzn. być w stanie ukryć wartości stałych, a więc zmodyfikować je zgodnie z potrzebami bez potrzeby pełnej rekompilacji), możesz zadeklarować ints jako extern w nagłówku i jako stałą w pliku CPP, jak w poniższym przykładzie:

// Header.hpp
namespace RecordType {
    extern const uint8 xNew ;
    extern const uint8 xDeleted ;
    extern const uint8 xModified ;
    extern const uint8 xExisting ;
}

I:

// Source.hpp
namespace RecordType {
    const uint8 xNew = 1;
    const uint8 xDeleted = 2;
    const uint8 xModified = 4;
    const uint8 xExisting = 8;
}

Nie będziesz jednak w stanie użyć switch na tych stałych. Więc w końcu wybierz swoją truciznę... :- p

 51
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-03 01:38:46

Czy wykluczyłeś std:: bitset? Do tego służą zestawy FLAG. Do

typedef std::bitset<4> RecordType;

Then

static const RecordType xNew(1);
static const RecordType xDeleted(2);
static const RecordType xModified(4);
static const RecordType xExisting(8);

Ponieważ istnieje kilka przeciążeń operatorów dla bitset, możesz teraz zrobić

RecordType rt = whatever;      // unsigned long or RecordType expression
rt |= xNew;                    // set 
rt &= ~xDeleted;               // clear 
if ((rt & xModified) != 0) ... // test

Lub coś bardzo podobnego - byłbym wdzięczny za wszelkie poprawki, ponieważ nie testowałem tego. Można również odwoływać się do bitów za pomocą indeksu, ale ogólnie najlepiej jest zdefiniować tylko jeden zestaw stałych, a Stałe Typu RecordType są prawdopodobnie bardziej użyteczne.

Zakładając, że wykluczyłeś bitset, Głosuję na enum .

Nie kupuję tego, że rzucanie enum jest poważną wadą-OK, więc jest trochę hałaśliwe , a przypisanie wartości poza zakresem do enum jest niezdefiniowanym zachowaniem, więc teoretycznie można strzelić sobie w stopę na jakichś nietypowych implementacjach C++. Ale jeśli robisz to tylko wtedy ,gdy jest to konieczne (czyli przechodząc z int do enum iirc), jest to całkowicie normalny kod, który ludzie widzieli wcześniej.

Mam wątpliwości co do kosztów przestrzeni w enum też. zmienne i parametry uint8 prawdopodobnie nie będą używać mniej stosu niż ints, więc liczy się tylko Przechowywanie w klasach. Jest kilka przypadków, w których pakowanie wielu bajtów w strukturę wygra (w takim przypadku można wrzucić enums do i z pamięci uint8), ale zwykle padding i tak zabije korzyść.

Więc enum nie ma żadnych wad w porównaniu z innymi, a jako zaleta daje trochę bezpieczeństwa typu (nie można przypisać jakiejś losowej wartości całkowitej bez jawnie casting) i czyste sposoby odwoływania się do wszystkiego.

Dla preferencji dodałbym również "= 2 " w enum, tak przy okazji. Nie jest to konieczne, ale "zasada najmniejszego zdziwienia" sugeruje, że wszystkie 4 definicje powinny wyglądać tak samo.

 29
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 01:48:45

Oto kilka artykułów na temat const vs. makra vs. enums:

Stałe Symboliczne
stałe wyliczania a obiekty stałe

Myślę, że powinieneś unikać makr zwłaszcza, że napisałeś większość swojego nowego kodu jest w nowoczesnym C++.

 8
Author: Abbas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-27 18:46:08

Jeśli to możliwe, nie używaj makr. Nie są zbyt podziwiani, jeśli chodzi o nowoczesne C++.

 5
Author: INS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 06:30:24

Liczby byłyby bardziej odpowiednie, ponieważ zapewniają "znaczenie identyfikatorom", a także bezpieczeństwo typu. Możesz wyraźnie powiedzieć, że "xDeleted" jest "RecordType" i że reprezentuje " typ rekordu "(wow!) nawet po latach. Consts wymagałby komentarzy do tego, również wymagałby przechodzenia w górę iw dół w kodzie.

 4
Author: hayalci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-10 10:49:30

Z definicjami i lose type safety

Niekoniecznie...
// signed defines
#define X_NEW      0x01u
#define X_NEW      (unsigned(0x01))  // if you find this more readable...

And with enum I lose some space (integers)

Niekoniecznie-ale musisz być wyraźny w miejscach przechowywania...

struct X
{
    RecordType recordType : 4;  // use exactly 4 bits...
    RecordType recordType2 : 4;  // use another 4 bits, typically in the same byte
    // of course, the overall record size may still be padded...
};

I prawdopodobnie muszę rzucać, gdy chcę wykonać operację bitową.

Możesz tworzyć operatory, aby pozbyć się bólu:

RecordType operator|(RecordType lhs, RecordType rhs)
{
    return RecordType((unsigned)lhs | (unsigned)rhs);
}

Z const myślę, że również tracę bezpieczeństwo typu, ponieważ losowy uint8 może wejdź przez pomyłkę.

To samo może się zdarzyć z każdym z tych mechanizmów: sprawdzanie zakresu i wartości jest zwykle ortogonalne do bezpieczeństwa typu (chociaż typy zdefiniowane przez użytkownika-tj. własne klasy-mogą wymusić "niezmienniki" dotyczące swoich danych). W przypadku enums kompilator może swobodnie wybrać większy typ do hostowania wartości, a niezainicjowana, uszkodzona lub po prostu pominięta zmienna enum może nadal interpretować swój wzorzec bitowy jako liczbę, której nie można się spodziewać - porównując nierówne do żadnej z tych wartości identyfikatory wyliczania, Dowolna ich kombinacja oraz 0.

Jest jakiś inny sposób czyszczenia? / Jeśli nie, to czego byś użył i dlaczego?

Cóż, w końcu sprawdzony i zaufany bitowy lub wyliczeń w stylu C działa całkiem dobrze, gdy masz pola bitowe i niestandardowe operatory na zdjęciu. Możesz dodatkowo poprawić swoją wytrzymałość za pomocą niestandardowych funkcji walidacji i twierdzeń, jak w odpowiedzi mat_geeka; techniki często równie odpowiednie do obsługi ciągu, int, podwójne wartości itp..

Można by argumentować, że to jest "czystsze": {]}
enum RecordType { New, Deleted, Modified, Existing };

showRecords([](RecordType r) { return r == New || r == Deleted; });

Jestem obojętny: bity danych pakują się ciaśniej, ale kod znacznie rośnie... zależy ile masz obiektów, a lamdbas-piękne, jakie są-nadal są messier i trudniejsze do uzyskania w prawo niż bitowe or.

BTW / - argument o bezpieczeństwie wątku jest dość słaby IMHO-najlepiej zapamiętać jako tła, a nie stać się dominującą siłą napędową decyzji; dzielenie się mutexem across the bitfields jest bardziej prawdopodobną praktyką, nawet jeśli nieświadomi ich pakowania (mutexy są stosunkowo nieporęcznymi członkami danych - muszę być naprawdę zaniepokojony wydajnością, aby rozważyć posiadanie wielu mutexów na członach jednego obiektu, i chciałbym spojrzeć na tyle uważnie, aby zauważyć, że są polami bitowymi). Każdy sub-word-size może mieć ten sam problem (np. A uint8_t). W każdym razie, możesz wypróbować atomic compare-and-swap style operations, jeśli desperacko potrzebujesz wyższej współbieżności.

 4
Author: Tony Delroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-03 04:05:47

Nawet jeśli musisz użyć 4 bajtów do przechowywania enum (nie jestem zbyt zaznajomiony z C++ - wiem, że możesz określić podstawowy typ W C#), nadal warto -- użyj enums.

W dzisiejszych czasach serwerów z GB pamięci, rzeczy takie jak 4 bajty vs 1 bajt pamięci na poziomie aplikacji w ogóle nie mają znaczenia. Oczywiście, jeśli w twojej konkretnej sytuacji użycie pamięci jest tak ważne (i nie możesz zmusić C++ do użycia bajtu do backupu enum), możesz rozważyć ' static / align = "left" /

Na koniec dnia musisz zadać sobie pytanie, czy warto używać "static const" dla 3 bajtów oszczędności pamięci dla struktury danych?

Należy pamiętać o czymś innym -- IIRC, na x86, struktury danych są wyrównane 4-bajtowo, więc jeśli nie masz wielu elementów o szerokości bajtów w swojej' rekordowej ' strukturze, może to nie mieć znaczenia. Przetestuj i upewnij się, że tak się stanie, zanim osiągniesz kompromis w zakresie konserwacji wydajności / przestrzeni.

 3
Author: Jonathan Rupp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 22:54:24

Jeśli chcesz mieć bezpieczeństwo typów klas, z wygodą składni wyliczania i sprawdzania bitów, rozważ bezpieczne etykiety w C++. Pracowałem z autorem i jest całkiem mądry.

Strzeżcie się. W końcu ten pakiet używa makr szablonów i !

 3
Author: Don Wakefield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 02:05:27

Czy rzeczywiście musisz przekazywać wartości flag jako konceptualną całość, czy będziesz miał dużo kodu dla flag? Tak czy inaczej, myślę, że posiadanie tego jako klasy lub struktury 1-bitowych pól bitowych może być bardziej przejrzyste:

struct RecordFlag {
    unsigned isnew:1, isdeleted:1, ismodified:1, isexisting:1;
};

Wtedy Klasa record może mieć zmienną składową struct RecordFlag, funkcje mogą przyjmować argumenty typu struct RecordFlag, itd. Kompilator powinien spakować bitfieldy razem, oszczędzając miejsce.

 2
Author: wnoise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 23:45:34

Prawdopodobnie nie używałbym enum do tego rodzaju rzeczy, gdzie wartości mogą być łączone ze sobą, bardziej typowo enum są wzajemnie wykluczającymi się stanami.

Ale bez względu na to, jakiej metody użyjesz, aby było bardziej jasne, że są to wartości, które są bitami, które można łączyć ze sobą, użyj tej składni zamiast rzeczywistych wartości:

#define X_NEW      (1 << 0)
#define X_DELETED  (1 << 1)
#define X_MODIFIED (1 << 2)
#define X_EXISTING (1 << 3)

Użycie przesunięcia w lewo pomaga wskazać, że każda wartość ma być pojedynczym bitem, jest mniej prawdopodobne, że później ktoś zrobi coś złego, jak dodać nową wartość i przypisać coś wartość 9.

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 02:03:37

Na podstawie KISS, wysoka spójność i niskie sprzężenie , zadaj te pytania-

    Kto musi wiedzieć? moja klasa, Moja biblioteka, inne klasy, inne biblioteki, strony trzecie
  • jaki poziom abstrakcji muszę zapewnić? Czy konsument rozumie operacje bitowe.
  • Czy muszę mieć interfejs z VB / C# itp?

Jest świetna książka " Projektowanie oprogramowania c++ na dużą skalę", Promuje typy bazowe zewnętrznie, jeśli można uniknąć inną zależnością od pliku nagłówka / interfejsu powinieneś spróbować.

 2
Author: titanae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 05:58:03

Jeśli używasz Qt powinieneś poszukać QFlags . Klasa QFlags zapewnia bezpieczny dla typu sposób przechowywania lub kombinacji wartości enum.

 2
Author: Thomas Koschel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 06:26:03

Wolę iść z

typedef enum { xNew = 1, xDeleted, xModified = 4, xExisting = 8 } RecordType;

Po prostu dlatego, że:

  1. jest czystszy i sprawia, że kod jest czytelny i możliwy do utrzymania.
  2. logicznie grupuje stałe.
  3. czas programisty jest ważniejszy, chyba że Twoim zadaniem jest zapisanie tych 3 bajtów.
 0
Author: Vivek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-21 23:27:00

Nie to, że lubię przesadzać z inżynierią wszystkiego, ale czasami w takich przypadkach może warto stworzyć (małą) klasę do hermetyzacji tych informacji. Jeśli utworzysz klasę RecordType, może ona mieć funkcje takie jak:

Void setDeleted ();

Void clearDeleted ();

Bool isDeleted ();

Itd... (lub jakakolwiek konwencja pasuje)

Może walidować kombinacje (w przypadku, gdy nie wszystkie kombinacje są legalne, np. być ustawione w tym samym czasie). Jeśli po prostu użyłeś masek bitowych itp., kod, który ustawia stan, musi zostać zweryfikowany, klasa może również enkapsulować tę logikę.

Klasa może również dać Ci możliwość dołączania znaczących informacji o logowaniu do każdego stanu, możesz dodać funkcję zwracającą reprezentację łańcucha bieżącego stanu itp. (lub użyć operatorów strumieniowych'

Dla tego wszystkiego, jeśli martwisz się o pamięć, nadal możesz mieć klasę, która ma tylko' char ' element danych, więc weź tylko niewielką ilość pamięci masowej (zakładając, że nie jest wirtualna). Oczywiście w zależności od sprzętu itp możesz mieć problemy z wyrównaniem.

Rzeczywiste wartości bitów mogą być niewidoczne dla reszty świata, jeśli znajdują się w anonimowej przestrzeni nazw wewnątrz pliku cpp, a nie w pliku nagłówkowym.

Jeśli okaże się, że kod używający enum / # define / bitmask itp. ma dużo kodu 'wsparcia' do radzenia sobie z nieprawidłowymi kombinacjami, logowaniem itp., to enkapsulacja w klasie może warto to rozważyć. Oczywiście w większości przypadków proste problemy są lepsze dzięki prostym rozwiązaniom...

 0
Author: Benjamin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-01 07:59:54