Hier ist eine Option für Bitmasken, wenn Sie die einzelnen Enum-Werte nicht verwenden können (z. B. müssen Sie sie nicht ausschalten) ... und wenn Sie sich keine Sorgen um die Aufrechterhaltung der Binärkompatibilität machen, dh: Sie Es ist mir egal, wo deine Teile leben ... was du wahrscheinlich bist. Außerdem sollten Sie sich nicht zu sehr mit dem Umfang und der Zugriffskontrolle befassen. Hmmm, Enums haben einige nette Eigenschaften für Bitfelder ... frage mich, ob das jemals jemand versucht hat :)
struct AnimalProperties
{
bool HasClaws : 1;
bool CanFly : 1;
bool EatsFish : 1;
bool Endangered : 1;
};
union AnimalDescription
{
AnimalProperties Properties;
int Flags;
};
void TestUnionFlags()
{
AnimalDescription propertiesA;
propertiesA.Properties.CanFly = true;
AnimalDescription propertiesB = propertiesA;
propertiesB.Properties.EatsFish = true;
if( propertiesA.Flags == propertiesB.Flags )
{
cout << "Life is terrible :(";
}
else
{
cout << "Life is great!";
}
AnimalDescription propertiesC = propertiesA;
if( propertiesA.Flags == propertiesC.Flags )
{
cout << "Life is great!";
}
else
{
cout << "Life is terrible :(";
}
}
Wir können sehen, dass das Leben großartig ist, wir haben unsere diskreten Werte und wir haben eine nette Beziehung zu & und | nach Herzenslust, der immer noch den Kontext dessen hat, was seine Teile bedeuten. Alles ist konsistent und vorhersehbar ... für mich ... solange ich weiterhin den VC ++ - Compiler von Microsoft mit Update 3 unter Win10 x64 verwende und meine Compiler-Flags nicht berühre :)
Obwohl alles großartig ist ... haben wir jetzt einen gewissen Kontext bezüglich der Bedeutung von Flags, da es sich um eine Vereinigung mit dem Bitfeld in der schrecklichen realen Welt handelt, in der Ihr Programm möglicherweise für mehr als eine einzelne diskrete Aufgabe verantwortlich ist, die Sie könnten immer noch versehentlich (ziemlich leicht) zwei Flaggenfelder verschiedener Gewerkschaften zusammenschlagen (z. B. AnimalProperties und ObjectProperties, da sie beide Ints sind) und all deine Teile durcheinander bringen, was ein schrecklicher Fehler ist, den man aufspüren kann ... und woher ich weiß Viele Leute in diesem Beitrag arbeiten nicht sehr oft mit Bitmasken, da das Erstellen einfach und die Wartung schwierig ist.
class AnimalDefinition {
public:
static AnimalDefinition *GetAnimalDefinition( AnimalFlags flags ); //A little too obvious for my taste... NEXT!
static AnimalDefinition *GetAnimalDefinition( AnimalProperties properties ); //Oh I see how to use this! BORING, NEXT!
static AnimalDefinition *GetAnimalDefinition( int flags ); //hmm, wish I could see how to construct a valid "flags" int without CrossFingers+Ctrl+Shift+F("Animal*"). Maybe just hard-code 16 or something?
AnimalFlags animalFlags; //Well this is *way* too hard to break unintentionally, screw this!
int flags; //PERFECT! Nothing will ever go wrong here...
//wait, what values are used for this particular flags field? Is this AnimalFlags or ObjectFlags? Or is it RuntimePlatformFlags? Does it matter? Where's the documentation?
//Well luckily anyone in the code base and get confused and destroy the whole program! At least I don't need to static_cast anymore, phew!
private:
AnimalDescription m_description; //Oh I know what this is. All of the mystery and excitement of life has been stolen away :(
}
Dann machen Sie Ihre Gewerkschaftserklärung privat, um den direkten Zugriff auf "Flags" zu verhindern, und müssen Getter / Setter und Operatorüberladungen hinzufügen, dann ein Makro für all das erstellen, und Sie sind im Grunde wieder da, wo Sie angefangen haben, als Sie es versucht haben Mach das mit einer Aufzählung.
Wenn Sie möchten, dass Ihr Code portabel ist, gibt es leider keine Möglichkeit, entweder A) das Bitlayout zu garantieren oder B) das Bitlayout zur Kompilierungszeit zu bestimmen (damit Sie es verfolgen und zumindest Änderungen korrigieren können) Versionen / Plattformen etc)
Offset in einer Struktur mit Bitfeldern
Zur Laufzeit können Sie Streiche spielen, indem Sie die Felder setzen und die Flags XOR-verknüpfen, um zu sehen, welche Bits sich geändert haben. Das klingt für mich ziemlich beschissen, obwohl Verse eine 100% konsistente, plattformunabhängige und vollständig deterministische Lösung haben, dh: eine ENUM.
TL; DR: Hör nicht auf die Hasser. C ++ ist kein Englisch. Nur weil die wörtliche Definition eines von C geerbten abgekürzten Schlüsselworts möglicherweise nicht zu Ihrer Verwendung passt, heißt das nicht, dass Sie es nicht verwenden sollten, wenn C und C ++ - Definition des Schlüsselworts Ihren Anwendungsfall absolut einschließt. Sie können auch Strukturen verwenden, um andere Dinge als Strukturen zu modellieren, und Klassen für andere Dinge als Schule und soziale Kaste. Sie können float für Werte verwenden, die geerdet sind. Sie können char für Variablen verwenden, die weder unverbrannt noch eine Person in einem Roman, Theaterstück oder Film sind. Jeder Programmierer, der zum Wörterbuch geht, um die Bedeutung eines Schlüsselworts vor der Sprachspezifikation zu bestimmen, ist ein ... Nun, ich werde meine Zunge dort halten.
Wenn Sie möchten, dass Ihr Code der gesprochenen Sprache nachempfunden ist, schreiben Sie am besten in Objective-C, das übrigens auch häufig Enums für Bitfelder verwendet.
[Flags]
, funktioniert das Attribut[Flags] enum class FlagBits{ Ready = 1, ReadMode = 2, WriteMode = 4, EOF = 8, Disabled = 16};