cpp
examples
examples.cpp⚙️cpp
/**
* Enums, Structs, and Unions - Examples
* Comprehensive demonstration of custom data types in C++
*/
#include <iostream>
#include <string>
#include <cstring>
#include <variant>
#include <type_traits>
#include <cmath>
using std::cout;
using std::endl;
using std::string;
// ============================================================================
// SECTION 1: Traditional Enums
// ============================================================================
// Traditional enum (C-style)
enum Color {
RED = 0,
GREEN = 1,
BLUE = 2
};
enum Priority {
LOW = 1,
MEDIUM = 5,
HIGH = 10,
CRITICAL = 100
};
void demonstrateTraditionalEnums() {
cout << "\n=== TRADITIONAL ENUMS ===" << endl;
Color c = RED;
Priority p = HIGH;
cout << "Color RED = " << c << endl;
cout << "Priority HIGH = " << p << endl;
// Implicit conversion to int (problematic!)
int colorValue = c;
cout << "Color as int: " << colorValue << endl;
// Can compare different enums (problematic!)
if (RED == LOW - 1) {
cout << "RED equals LOW - 1 (both are 0) - This is problematic!" << endl;
}
// Switch statement
switch (p) {
case LOW: cout << "Low priority" << endl; break;
case MEDIUM: cout << "Medium priority" << endl; break;
case HIGH: cout << "High priority" << endl; break;
case CRITICAL: cout << "CRITICAL priority!" << endl; break;
}
}
// ============================================================================
// SECTION 2: Enum Class (Scoped Enums)
// ============================================================================
// Strongly typed enum class
enum class Direction {
North,
South,
East,
West
};
enum class TrafficLight {
Red,
Yellow,
Green
};
// With underlying type
enum class ErrorCode : uint16_t {
None = 0,
NotFound = 404,
ServerError = 500,
Timeout = 408
};
// Small enum for memory efficiency
enum class DayOfWeek : uint8_t {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
// Helper function to convert enum class to underlying type
template<typename E>
constexpr auto toUnderlying(E e) noexcept {
return static_cast<std::underlying_type_t<E>>(e);
}
void demonstrateEnumClass() {
cout << "\n=== ENUM CLASS (SCOPED ENUMS) ===" << endl;
Direction dir = Direction::North;
TrafficLight light = TrafficLight::Red;
ErrorCode error = ErrorCode::NotFound;
DayOfWeek day = DayOfWeek::Monday;
// Must use explicit cast to get int value
cout << "Direction::North = " << static_cast<int>(dir) << endl;
cout << "TrafficLight::Red = " << static_cast<int>(light) << endl;
cout << "ErrorCode::NotFound = " << toUnderlying(error) << endl;
// Size comparison
cout << "\nSize comparison:" << endl;
cout << "sizeof(Direction) = " << sizeof(Direction) << " bytes" << endl;
cout << "sizeof(ErrorCode) = " << sizeof(ErrorCode) << " bytes" << endl;
cout << "sizeof(DayOfWeek) = " << sizeof(DayOfWeek) << " byte" << endl;
// Type-safe comparisons
// if (dir == light) {} // Compile error! Different types
if (dir == Direction::North) {
cout << "\nHeading North!" << endl;
}
// Switch with enum class
switch (light) {
case TrafficLight::Red: cout << "STOP!" << endl; break;
case TrafficLight::Yellow: cout << "Caution..." << endl; break;
case TrafficLight::Green: cout << "GO!" << endl; break;
}
}
// ============================================================================
// SECTION 3: Basic Structs
// ============================================================================
// Simple struct
struct Point2D {
double x;
double y;
};
// Struct with default values (C++11)
struct Point3D {
double x = 0.0;
double y = 0.0;
double z = 0.0;
};
// Struct with methods
struct Rectangle {
double width;
double height;
// Member functions
double area() const { return width * height; }
double perimeter() const { return 2 * (width + height); }
double diagonal() const { return std::sqrt(width*width + height*height); }
// Mutating function
void scale(double factor) {
width *= factor;
height *= factor;
}
// Static factory method
static Rectangle square(double side) {
return {side, side};
}
// Print function
void print() const {
cout << "Rectangle(" << width << " x " << height
<< ", area=" << area() << ")" << endl;
}
};
void demonstrateBasicStructs() {
cout << "\n=== BASIC STRUCTS ===" << endl;
// Different initialization styles
Point2D p1; // Uninitialized (garbage values!)
Point2D p2 = {3.0, 4.0}; // Aggregate initialization
Point2D p3{1.0, 2.0}; // Uniform initialization (C++11)
Point2D p4 = {}; // Zero initialization
// Point3D has default values
Point3D p5; // All zeros due to defaults
Point3D p6{1.0, 2.0}; // z defaults to 0.0
cout << "p2: (" << p2.x << ", " << p2.y << ")" << endl;
cout << "p3: (" << p3.x << ", " << p3.y << ")" << endl;
cout << "p5: (" << p5.x << ", " << p5.y << ", " << p5.z << ")" << endl;
cout << "p6: (" << p6.x << ", " << p6.y << ", " << p6.z << ")" << endl;
// Rectangle with methods
Rectangle rect{10.0, 5.0};
rect.print();
cout << "Diagonal: " << rect.diagonal() << endl;
rect.scale(2.0);
cout << "After scaling by 2: ";
rect.print();
// Static factory
Rectangle sq = Rectangle::square(5.0);
cout << "Square: ";
sq.print();
}
// ============================================================================
// SECTION 4: Nested Structs
// ============================================================================
struct Address {
string street;
string city;
string state;
string zipCode;
string country;
void print() const {
cout << street << endl;
cout << city << ", " << state << " " << zipCode << endl;
cout << country << endl;
}
};
struct Person {
string firstName;
string lastName;
int age;
Address address; // Nested struct
string fullName() const {
return firstName + " " + lastName;
}
void print() const {
cout << "Name: " << fullName() << endl;
cout << "Age: " << age << endl;
cout << "Address:" << endl;
address.print();
}
};
struct Company {
string name;
Address headquarters;
Person ceo;
int employeeCount;
void print() const {
cout << "Company: " << name << endl;
cout << "Employees: " << employeeCount << endl;
cout << "CEO: " << ceo.fullName() << endl;
cout << "Headquarters:" << endl;
headquarters.print();
}
};
void demonstrateNestedStructs() {
cout << "\n=== NESTED STRUCTS ===" << endl;
Person person = {
"John",
"Doe",
35,
{"123 Main St", "New York", "NY", "10001", "USA"}
};
person.print();
cout << "\n--- Company Example ---" << endl;
Company company = {
"TechCorp Inc.",
{"456 Tech Blvd", "San Francisco", "CA", "94102", "USA"},
{"Jane", "Smith", 45, {"789 Exec Lane", "San Francisco", "CA", "94103", "USA"}},
5000
};
company.print();
}
// ============================================================================
// SECTION 5: Struct Memory Layout
// ============================================================================
// Struct with potential padding
struct Padded {
char a; // 1 byte
// 3 bytes padding (to align int)
int b; // 4 bytes
char c; // 1 byte
// 3 bytes padding (to align struct size to 4)
};
// Reorganized to minimize padding
struct Optimized {
int b; // 4 bytes
char a; // 1 byte
char c; // 1 byte
// 2 bytes padding (to align struct size to 4)
};
// Packed struct (no padding, slower access)
#pragma pack(push, 1)
struct Packed {
char a; // 1 byte
int b; // 4 bytes
char c; // 1 byte
};
#pragma pack(pop)
void demonstrateMemoryLayout() {
cout << "\n=== STRUCT MEMORY LAYOUT ===" << endl;
cout << "Padded struct layout:" << endl;
cout << " sizeof(Padded) = " << sizeof(Padded) << " bytes" << endl;
cout << " Members: char(1) + int(4) + char(1) = 6 bytes" << endl;
cout << " With padding: 12 bytes" << endl;
cout << "\nOptimized struct layout:" << endl;
cout << " sizeof(Optimized) = " << sizeof(Optimized) << " bytes" << endl;
cout << " Members: int(4) + char(1) + char(1) = 6 bytes" << endl;
cout << " With padding: 8 bytes" << endl;
cout << "\nPacked struct layout:" << endl;
cout << " sizeof(Packed) = " << sizeof(Packed) << " bytes" << endl;
cout << " Members: char(1) + int(4) + char(1) = 6 bytes" << endl;
cout << " No padding (may be slower!)" << endl;
// Show offsets
cout << "\nPadded member offsets:" << endl;
cout << " offsetof(Padded, a) = " << offsetof(Padded, a) << endl;
cout << " offsetof(Padded, b) = " << offsetof(Padded, b) << endl;
cout << " offsetof(Padded, c) = " << offsetof(Padded, c) << endl;
}
// ============================================================================
// SECTION 6: Basic Unions
// ============================================================================
union IntFloat {
int i;
float f;
};
union MultiType {
int8_t byte;
int16_t word;
int32_t dword;
int64_t qword;
float single;
double dbl;
};
void demonstrateBasicUnions() {
cout << "\n=== BASIC UNIONS ===" << endl;
IntFloat u;
cout << "sizeof(IntFloat) = " << sizeof(u) << " bytes" << endl;
u.i = 42;
cout << "After u.i = 42:" << endl;
cout << " u.i = " << u.i << endl;
cout << " u.f = " << u.f << " (garbage - wrong type!)" << endl;
u.f = 3.14f;
cout << "\nAfter u.f = 3.14f:" << endl;
cout << " u.f = " << u.f << endl;
cout << " u.i = " << u.i << " (garbage - wrong type!)" << endl;
// MultiType union
cout << "\nMultiType union sizes:" << endl;
cout << " sizeof(MultiType) = " << sizeof(MultiType) << " bytes" << endl;
cout << " (Size of largest member: double = 8 bytes)" << endl;
}
// ============================================================================
// SECTION 7: Tagged Union (Discriminated Union)
// ============================================================================
enum class ValueType { Integer, Float, String };
struct TaggedValue {
ValueType type;
union {
int intValue;
float floatValue;
char stringValue[32]; // Fixed-size string buffer
};
// Factory methods
static TaggedValue fromInt(int v) {
TaggedValue tv;
tv.type = ValueType::Integer;
tv.intValue = v;
return tv;
}
static TaggedValue fromFloat(float v) {
TaggedValue tv;
tv.type = ValueType::Float;
tv.floatValue = v;
return tv;
}
static TaggedValue fromString(const char* s) {
TaggedValue tv;
tv.type = ValueType::String;
strncpy(tv.stringValue, s, 31);
tv.stringValue[31] = '\0';
return tv;
}
void print() const {
switch (type) {
case ValueType::Integer:
cout << "Integer: " << intValue << endl;
break;
case ValueType::Float:
cout << "Float: " << floatValue << endl;
break;
case ValueType::String:
cout << "String: " << stringValue << endl;
break;
}
}
};
void demonstrateTaggedUnion() {
cout << "\n=== TAGGED UNION ===" << endl;
TaggedValue values[] = {
TaggedValue::fromInt(42),
TaggedValue::fromFloat(3.14159f),
TaggedValue::fromString("Hello, World!")
};
for (const auto& v : values) {
v.print();
}
cout << "\nsizeof(TaggedValue) = " << sizeof(TaggedValue) << " bytes" << endl;
}
// ============================================================================
// SECTION 8: std::variant (C++17 Type-Safe Union)
// ============================================================================
void demonstrateStdVariant() {
cout << "\n=== std::variant (C++17) ===" << endl;
// Type-safe union
std::variant<int, float, string> value;
value = 42;
cout << "Stored int: " << std::get<int>(value) << endl;
cout << " index() = " << value.index() << endl;
value = 3.14f;
cout << "\nStored float: " << std::get<float>(value) << endl;
cout << " index() = " << value.index() << endl;
value = string("Hello variant!");
cout << "\nStored string: " << std::get<string>(value) << endl;
cout << " index() = " << value.index() << endl;
// Safe access with get_if
cout << "\nSafe access with get_if:" << endl;
if (auto* pInt = std::get_if<int>(&value)) {
cout << " It's an int: " << *pInt << endl;
} else if (auto* pFloat = std::get_if<float>(&value)) {
cout << " It's a float: " << *pFloat << endl;
} else if (auto* pStr = std::get_if<string>(&value)) {
cout << " It's a string: " << *pStr << endl;
}
// std::visit for pattern matching
cout << "\nUsing std::visit:" << endl;
value = 100;
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
cout << " Visiting int: " << arg << endl;
} else if constexpr (std::is_same_v<T, float>) {
cout << " Visiting float: " << arg << endl;
} else if constexpr (std::is_same_v<T, string>) {
cout << " Visiting string: " << arg << endl;
}
}, value);
// holds_alternative
cout << "\nholds_alternative checks:" << endl;
cout << " holds int? " << std::holds_alternative<int>(value) << endl;
cout << " holds float? " << std::holds_alternative<float>(value) << endl;
cout << " holds string? " << std::holds_alternative<string>(value) << endl;
}
// ============================================================================
// SECTION 9: Bit Fields
// ============================================================================
struct StatusFlags {
unsigned int isActive : 1; // 1 bit
unsigned int isEnabled : 1; // 1 bit
unsigned int priority : 3; // 3 bits (0-7)
unsigned int errorCode : 4; // 4 bits (0-15)
unsigned int reserved : 23; // 23 bits
};
// Compact color representation
struct Color8 {
uint32_t red : 8;
uint32_t green : 8;
uint32_t blue : 8;
uint32_t alpha : 8;
};
// IP packet flags
struct IPFlags {
uint8_t reserved : 1;
uint8_t dontFragment : 1;
uint8_t moreFragments : 1;
uint8_t unused : 5;
};
void demonstrateBitFields() {
cout << "\n=== BIT FIELDS ===" << endl;
StatusFlags status = {};
status.isActive = 1;
status.isEnabled = 1;
status.priority = 5;
status.errorCode = 12;
cout << "StatusFlags:" << endl;
cout << " isActive = " << status.isActive << endl;
cout << " isEnabled = " << status.isEnabled << endl;
cout << " priority = " << status.priority << " (max 7)" << endl;
cout << " errorCode = " << status.errorCode << " (max 15)" << endl;
cout << " sizeof(StatusFlags) = " << sizeof(StatusFlags) << " bytes" << endl;
// Color
Color8 color = {255, 128, 64, 255};
cout << "\nColor8 RGBA:" << endl;
cout << " R=" << color.red << " G=" << color.green
<< " B=" << color.blue << " A=" << color.alpha << endl;
cout << " sizeof(Color8) = " << sizeof(Color8) << " bytes" << endl;
// IP Flags
IPFlags ip = {};
ip.dontFragment = 1;
cout << "\nIP Flags:" << endl;
cout << " dontFragment = " << (int)ip.dontFragment << endl;
cout << " sizeof(IPFlags) = " << sizeof(IPFlags) << " byte" << endl;
}
// ============================================================================
// SECTION 10: Practical Examples
// ============================================================================
// Game entity state
enum class EntityState : uint8_t {
Idle,
Moving,
Attacking,
Dead
};
struct GameEntity {
uint32_t id;
float x, y, z;
float health;
EntityState state;
struct Stats {
int strength;
int agility;
int intelligence;
} stats;
bool isAlive() const { return state != EntityState::Dead && health > 0; }
void takeDamage(float damage) {
health -= damage;
if (health <= 0) {
health = 0;
state = EntityState::Dead;
}
}
void print() const {
cout << "Entity #" << id << endl;
cout << " Position: (" << x << ", " << y << ", " << z << ")" << endl;
cout << " Health: " << health << endl;
cout << " State: " << static_cast<int>(state) << endl;
cout << " Stats: STR=" << stats.strength
<< " AGI=" << stats.agility
<< " INT=" << stats.intelligence << endl;
}
};
// Configuration with variant
struct AppConfig {
using ConfigValue = std::variant<int, double, bool, string>;
string name;
ConfigValue value;
void print() const {
cout << name << " = ";
std::visit([](auto&& v) {
using T = std::decay_t<decltype(v)>;
if constexpr (std::is_same_v<T, bool>) {
cout << (v ? "true" : "false");
} else {
cout << v;
}
}, value);
cout << endl;
}
};
void demonstratePracticalExamples() {
cout << "\n=== PRACTICAL EXAMPLES ===" << endl;
// Game entity
cout << "Game Entity:" << endl;
GameEntity player = {
1, // id
100.0f, 50.0f, 0.0f, // position
100.0f, // health
EntityState::Idle,
{10, 15, 8} // stats
};
player.print();
player.takeDamage(30);
cout << "\nAfter taking 30 damage:" << endl;
cout << " Health: " << player.health << endl;
cout << " Alive: " << (player.isAlive() ? "Yes" : "No") << endl;
// Configuration values
cout << "\nApp Configuration:" << endl;
AppConfig configs[] = {
{"window_width", 1920},
{"render_scale", 1.5},
{"fullscreen", true},
{"player_name", string("Player1")}
};
for (const auto& config : configs) {
config.print();
}
}
// ============================================================================
// MAIN
// ============================================================================
int main() {
cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ ENUMS, STRUCTS, AND UNIONS EXAMPLES ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demonstrateTraditionalEnums();
demonstrateEnumClass();
demonstrateBasicStructs();
demonstrateNestedStructs();
demonstrateMemoryLayout();
demonstrateBasicUnions();
demonstrateTaggedUnion();
demonstrateStdVariant();
demonstrateBitFields();
demonstratePracticalExamples();
cout << "\n═══════════════════════════════════════════════════════════════" << endl;
cout << "All examples completed!" << endl;
return 0;
}