- Learn C++ Test Site - https://test.learncpp.com -

8.2 — Introduction to program-defined types

Because fundamental types have been defined as part of the core C++ language, they are available for immediate use. For example, if we want to define an int variable, we can just do so:

This also works for the compound types that are simple extensions of fundamental types (including pointers, references, and arrays):

However, the enumerated types and class types bring one other neat ability to the table: the ability to create new, custom types for use in our own programs! Such types are called program-defined types.

Just like functions and variables must before defined before we can use them, program-defined types must be defined before we can use them.

For example:

Ignoring what a struct is for the moment, you can see that we’re defining a new struct type named Fraction (in the global scope, so it can be used anywhere in the rest of the file). Then, inside main(), we instantiate a variable of type Fraction.

We’ll show more examples of defining and using program-defined types in the next lesson (8.2 -- Introduction to unscoped enumerations [1]), and we cover structs starting in lesson 8.12 -- Struct definition and member selection [2].

By convention, program-defined types are named starting with a capital letter and don’t use a “_t” suffix (e.g. Fraction, not fraction or fraction_t). This nomenclature helps differentiate program-defined type names from from type aliases (which often use a “_t” suffix) and variable names (which start with a lower case letter).

Best practice

Whenever you create a new program-defined type, name it starting with a capital letter.

New programmers are sometimes confused by the following:

Because Fraction starts with a capital letter, by convention we can recognize that it is a program-defined type. And fraction is the name of the variable being created. C++ is case-sensitive, so there’s no naming conflict here!

Using program-defined types throughout a multi-file program

Every code file that uses a program-defined type needs to see the full type definition before it is used. A forward declaration is not sufficient. This is required so that the compiler knows how much memory to allocate for objects of that type.

To propagate type definitions into the code files that need them, program-defined types are typically defined in header files, and then #included into any code file that requires that type definition. These header files are typically given the same name as the program-defined type (e.g. a program-defined type named Fraction would be defined in Fraction.h)

Best practice

A program-defined type used in only one code file should be defined in that code file as close to the first point of use as possible.

A program-defined type used in multiple code files should be defined in a header files with the same name as the program defined type and then #included into each code file as needed.



For advanced readers

In lesson 2.7 -- Forward declarations and definitions [3], we discussed how the one-definition rule required us to define functions (and variables) in code files (not headers), and propagate only the forward declarations via header files.

If program-defined types were subject to the same limitations, we would only be able to propagate forward declarations for types, not the full type definitions. This isn’t sufficient for us to be able to use those type definitions (since the compiler needs to see the full type definition).

Consequently, types have been exempted from the one-definition rule, so that full type definitions can be propagated to multiple files, even if that results in a duplicate definition.

User-defined types

The term user-defined type sometimes comes up in casual conversation, as well as being mentioned (but not defined) in the C++ language standard. In casual conversation, the term tends to mean “a type that you defined yourself” (in other words, a program-defined type). Sometimes this also includes type aliases.

However, as used in the C++ language standard, a user-defined type is intended to be any type not defined as part of the core C++ language. This means that types defined in the C++ standard library are technically considered to be user-defined types.

Because of mismatch in casual vs technical meaning, we’ll generally avoid the term user-defined type, and prefer the term program-defined type when talking about types that are defined by a programmer for use in their own programs.