Enums and Structs recap

Congratulations! You've completed this section. The knowledge you've gained about structs will be invaluable when we reach C++'s most important topic: classes!

Program-Defined Types

A program-defined type (also called a user-defined type) is a custom type we can create for use in our programs. Enumerated types and class types (including structs, classes, and unions) allow creation of program-defined types. Program-defined types must be defined before use. The definition of a program-defined type is called a type definition. Type definitions are exempt from the one-definition rule.

Enumerations

An enumeration (also called an enumerated type or an enum) is a compound data type where every possible value is defined as a symbolic constant (called an enumerator). Enumerations are distinct types, meaning the compiler can differentiate them from other types (unlike type aliases).

Unscoped enumerations are named such because they put their enumerator names into the same scope as the enumeration definition itself (as opposed to creating a new scope region like a namespace does). Unscoped enumerations also provide a named scope region for their enumerators. Unscoped enumerations will implicitly convert to integral values.

Scoped enumerations work similarly to unscoped enumerations but won't implicitly convert to integers, and the enumerators are only placed into the scope region of the enumeration (not into the scope region where the enumeration is defined).

Structs

A struct (short for structure) is a program-defined data type that allows us to bundle multiple variables together into a single type. The variables that are part of the struct (or class) are called data members (or member variables). To access a specific member variable, we use the member selection operator (operator.) in between the struct variable name and the member name (for normal structs and references to structs), or the member selection from pointer operator (operator->) (for pointers to structs).

Aggregates and Initialization

In general programming, an aggregate data type (also called an aggregate) is any type that can contain multiple data members. In C++, arrays and structs with only data members are aggregates.

Aggregates use a form of initialization called aggregate initialization, which allows us to directly initialize the members of aggregates. To do this, we provide an initializer list as an initializer, which is just a list of comma-separated values. Aggregate initialization does a memberwise initialization, which means each member in the struct is initialized in the order of declaration.

In C++20, designated initializers allow you to explicitly define which initialization values map to which members. The members must be initialized in the order in which they are declared in the struct, otherwise an error will result.

Default Member Initializers

When we define a struct (or class) type, we can provide a default initialization value for each member as part of the type definition. This process is called non-static member initialization, and the initialization value is called a default member initializer.

Struct Memory Layout

For performance reasons, the compiler will sometimes add gaps into structures (this is called padding), so the size of a structure may be larger than the sum of the size of its members.

Class Templates

A class template is a template definition for instantiating class types (structs, classes, or unions). Class template argument deduction (CTAD) is a C++17 feature that allows the compiler to deduce the template type arguments from an initializer.

Key Terminology

  • Program-defined type: Custom type created for use in your programs
  • User-defined type: Another name for program-defined type
  • Type definition: The definition of a program-defined type
  • Enumeration/Enum: Compound type where every value is a symbolic constant
  • Enumerator: A symbolic constant defined within an enumeration
  • Distinct type: A type the compiler can differentiate from other types
  • Unscoped enumeration: Enumeration placing enumerators in the enclosing scope
  • Scoped enumeration: Enumeration placing enumerators only in the enum's scope
  • Named scope region: Scope region provided by unscoped enumerations
  • Struct/Structure: Program-defined type bundling multiple variables
  • Data member: Variable that is part of a struct or class
  • Member variable: Another name for data member
  • Member selection operator (.): Operator for accessing struct members
  • Member selection from pointer operator (->): Operator for accessing members via pointer
  • Aggregate: Type that can contain multiple data members
  • Aggregate initialization: Initialization using an initializer list
  • Initializer list: Comma-separated list of values for initialization
  • Memberwise initialization: Initializing each member in declaration order
  • Designated initializers: C++20 feature for explicitly mapping values to members
  • Non-static member initialization: Providing default values in type definition
  • Default member initializer: Default initialization value for a member
  • Padding: Gaps added by compiler in structures for performance
  • Class template: Template definition for instantiating class types
  • Class template argument deduction (CTAD): Compiler deduction of template type arguments

Looking Forward

The concepts you've learned in this section—program-defined types, enumerations, and structs—form the foundation for understanding C++ classes. You've seen how to create custom types, bundle data together, and initialize complex objects. These skills will be essential as you move forward to learn about classes, which extend structs with additional capabilities like member functions, constructors, and access control. Keep practicing these fundamentals, as they're the building blocks of object-oriented programming in C++.