Concepts / Built-in Types in C++

Built-in Types in C++

A concrete class is a class designed so that its objects behave just like built-in types.

  • Programming

A Type That Acts Like int

Most of the types you have used so far come with the language itself. An int holds a whole number, and an array holds a fixed run of elements of one kind. These are built-in types. Now imagine a type that a programmer designs and writes as a class, yet that can be used in almost the same way as those built-in types. That idea is the subject of this article: concrete classes.

Keep one question in mind while you read: when a class is written to behave like a built-in type, what exactly is shared with the built-in type, and what is left different? You will trace the answer step by step through an example, then check it against the source's pairings of types.

Built-in Types as Starting Material

Think of a built-in type as the material you start from. When you write int total = 0; you create a value, you combine it with other values using operations the language supplies, and you pass it through your program in familiar ways. Nothing about that usage needs explaining: it is the baseline pattern of working with values in C++.

A concrete class asks a different question. Instead of accepting the language's operations as given, the programmer defines a type whose values can be used with that same familiar pattern. The source's central claim is that the user-defined type can be used in almost the same way as the built-in one, even though the two are not the same thing.

What a Concrete Class Is

Definition

A concrete class is a class designed so that its objects behave just like built-in types.

The word concrete here signals that the class is a complete, usable value type: its objects are meant to be created, combined, and passed around the way built-in values are. A concrete class does not have to reproduce every detail of the built-in type it resembles. Its job is to make its objects feel like ordinary values in a program.

Pairing Concrete Classes With Their Built-in Models

The source frames the idea through two comparisons. A complex number type and an infinite-precision integer are each much like the built-in int. A vector and a string are each much like a built-in array. In both comparisons, the user-defined type is close enough to its built-in counterpart that it can be understood through that counterpart, even though it is not the same thing.

Concrete classBuilt-in type it resemblesWhat is shared in useWhere it differs
Complex number typeintValues are created, combined with operators, and passed through a programIts operations are defined by the class, not supplied by the language
Infinite-precision integerintInteger-like values used in the same familiar wayIts semantics and its own set of operations belong to the class
VectorBuilt-in arrayCollections of elements handled in familiar waysDescribed in the source as better behaved than the built-in array
StringBuilt-in arrayText handled as a value in familiar waysDescribed in the source as better behaved than the built-in array

The source pairs each concrete class with the built-in type it is meant to resemble. Every row names a difference as well as a similarity.

The pairs show that the resemblance concerns the role each type plays in a program, not how it is built inside. A complex number and an int play similar roles as quantities you calculate with. A vector and an array play similar roles as containers of elements. The internal workings can differ widely while the usage pattern stays familiar.

Tracing an Addition on a Complex Number

A complex number is a good illustration because it is a quantity that people often wish to add and track just as they would a plain number. The example below is written for this article, not taken from the source. It defines a small complex number class that stores a real part and an imaginary part, and it defines its own addition operation. Read it with the source's idea in mind: the class can be used the way a number is used, and the addition it performs is the class's own definition.

cpp
Output
(4, 1)
Walk through it
  1. 1
    Complex a(1.0, 2.0) creates a value whose real part is 1 and imaginary part is 2.
  2. 2
    Complex b(3.0, -1.0) creates a second value with real part 3 and imaginary part -1.
  3. 3
    The expression a + b calls the operator+ member function on a, passing b as other.
  4. 4
    Inside operator+, the real parts are added (1 + 3 = 4) and the imaginary parts are added (2 + -1 = 1), and a new Complex is returned.
  5. 5
    That returned value is stored in c, and printing c's parts produces (4, 1).
Notes on the code
  • The class stores its two parts as private members
  • operator+ defines what the plus sign means for Complex values
  • The expression a + b in main looks like ordinary arithmetic

What do you think happens?

Before reading on, what do you expect the program to print?

Reveal answer
Answer:

(4, 1)

The real parts 1 and 3 sum to 4, and the imaginary parts 2 and -1 sum to 1, so the printed pair is (4, 1).

Worked example

Following the value of c through the addition

Trace what happens to the values a, b, and c when the statement Complex c = a + b; runs.

  1. 1
    Start with a and b

    a holds real 1 and imaginary 2. b holds real 3 and imaginary -1. Neither has changed yet.

  2. 2
    Dispatch the plus sign

    The compiler sees a + b with a Complex on each side and uses the operator+ that the class defined, not an addition the language supplies for int.

  3. 3
    Compute the real part

    Inside the class, re_ of a (1) plus other.re_ of b (3) gives 4.

  4. 4
    Compute the imaginary part

    im_ of a (2) plus other.im_ of b (-1) gives 1.

  5. 5
    Store the result

    The new Complex (4, 1) is the value that initializes c. The originals a and b are unchanged.

Result

c holds real 4 and imaginary 1. a and b still hold their original values.

The plus sign in main looks like the ordinary arithmetic you already know, which is the resemblance to int that the source describes. But the addition itself lives inside the class. Had the programmer defined operator+ differently, the same visible syntax would mean something else. This is the second half of the source's point: the operations belong to the concrete type.

Shared Pattern Versus Own Operations

The source names two things that a concrete class and the built-in type it resembles share. The first is the overall pattern of use: you create values, combine them, and move them through a program in familiar ways. The second is the sense that the type is a sound, well-formed value rather than a loose collection of parts. Beyond that shared pattern, the concrete class is free to define what its own operations mean.

The diagram below sets a built-in int beside a user-defined complex number type. Both are used by writing values and operations on them, but the operations come from different places: the built-in int uses the operations the language supplies, while the complex type supplies its own.

Create valuesshared patternCreate valuesshared patternCombine valuesshared patternCombine valuesshared patternOperations from thelanguageown operationsOperations from theclassown operations
What do a built-in int and a concrete Complex class share in use, and where do their operations come from?

Read the two columns across. Each row of shared pattern matches, so a reader familiar with int can start using the complex type immediately. The bottom row is where they separate: the int's operations are supplied by the language, while the complex type's operations are whatever its class defines.

Three Ingredients That Make a Type Built-in

Built-in types can be built from the fundamental types, the const modifier, and the declarator operators. It helps to read this definition as a recipe with three inputs. The first input is the set of fundamental types. The second is the const modifier, which marks a value as one that should not change. The third is the set of declarator operators, which shape how a declaration names and structures a type. A built-in type is whatever the language lets you form by combining these three inputs.

Fundamental typesBuilt-in typeconst modifierDeclarator operatorscombine intocombine intocombine into
Which three ingredients combine to form a built-in type, and how does each connect to the result?

Read the diagram as a set of three inputs feeding one result. None of the three inputs is a complete built-in type on its own; each one contributes a part, and the combination is what the language recognizes as a built-in type.

cpp
Notes on the code
  • int is a fundamental type
  • const marks speed_limit as a value that should not change
  • The declaration combines the fundamental type with the const modifier

This declaration does not invent a new kind of type with its own operations. It combines a fundamental type with the const modifier, which is exactly the recipe the definition names. The source does not list every possible combination, so treat this as one illustration of the general principle rather than a complete catalogue.

Why C++ Keeps Built-in Types Low-Level

Imagine you need a language in which a programmer can write a fast program with almost no hidden cost, where every operation maps onto something the machine actually does. C++ begins from that requirement. Its built-in types and operations are rich, but they are deliberately low-level, and they reflect the capabilities of conventional computer hardware directly and efficiently.

A low-level foundation has a consequence. The built-in types do not give you high-level facilities that make advanced applications easy to write. The language therefore adds a second layer: a set of abstraction mechanisms that programmers use to build those higher-level facilities themselves. Keep that two-layer picture in mind, because the rest of this section is about how the layers connect.

Built-in Types Versus User-Defined Types

Built-in types are the starting material. Abstraction mechanisms are the tools that turn that material into something larger. The source describes these mechanisms as a sophisticated set that C++ adds on top of the built-in types and operations. Programmers use them to build high-level facilities out of the low-level base.

The purpose of these mechanisms is specific. They are primarily designed to let programmers design and implement their own types, with suitable representations and operations. They also let programmers use those types simply and elegantly once they exist. So the abstraction mechanisms serve two audiences in one move: the person who designs the type and the person who later uses it.

When a programmer uses the abstraction mechanisms to build a type, the result is called a user-defined type. The source gives two names for this kind of type: classes and enumerations. Concrete classes such as the complex number type above are one kind of user-defined type. Most of the source book is devoted to the design, implementation, and use of user-defined types, which shows how central this category is to working in C++.

Built-in typesAbstractionmechanismsUser-defined typesClassesEnumerationsaugmented byused to buildincludesincludesconstructed out of
How do built-in types and user-defined types relate, and where do abstraction mechanisms sit between them?

Read the diagram from the top down. The built-in layer is the foundation at the top, augmented by abstraction mechanisms. Those mechanisms are the means by which user-defined types are built. User-defined types are also constructed directly out of the built-in types, so the built-in layer stays the foundation even at the top of the stack.

The source also notes that the standard library mainly consists of user-defined types. Those library components show what can be built with the language facilities and programming techniques the early chapters introduce. The standard library is a good place to see user-defined types at work once you understand the built-in foundation.

Mistakes Beginners Make With This Idea

  • Common mistake

    Assuming a concrete class works exactly like the built-in type it resembles

    What it looks like

    Believing that a complex number type must behave identically to int in every operation

    Why it fails

    The source says the resemblance is about how the type is used. Concrete classes keep their own semantics and their own sets of operations.

    Do this instead

    Use the shared pattern to get started, then check the class's own definitions for what each operation actually does.

  • Common mistake

    Thinking the same visible syntax always means the same thing

    What it looks like

    Reading a + b as ordinary addition even when a and b are a user-defined Complex type

    Why it fails

    The meaning of + for Complex comes from the operator+ the class defines, so a different definition would change the result.

    Do this instead

    Look for the operator definition inside the class when an expression uses a user-defined type.

  • Common mistake

    Treating a built-in type as a single unbreakable word

    What it looks like

    Reading const int as one indivisible keyword with one meaning

    Why it fails

    The definition says built-in types are built by combining fundamental types, the const modifier, and declarator operators.

    Do this instead

    Read the declaration as a combination of parts and identify which ingredient each part supplies.

  • Common mistake

    Confusing low-level with limited: built-in types are rich, but they do not supply high-level facilities by themselves

Checking Your Understanding

MEDIUM

A class Vector is written so that its objects can be created, combined, and passed through a program in the same way as built-in arrays. Explain what is shared between Vector and the built-in array, and name one thing that the class is free to define for itself.

Hints
  • Look for the phrase the resemblance is about how the type is used.
  • The source says concrete classes keep their own semantics and operations.
  • Consider what the vector's own operations might mean, separate from the array's usage pattern.
EASY

Name the three ingredients that combine to form a built-in type, then decide which one the declaration const double rate = 0.05; relies on for its const part.

Hints
  • The three ingredients are fundamental types, the const modifier, and declarator operators.
  • Find the word that marks a value as one that should not change.

Key Takeaways

  • A concrete class is a class designed so that its objects behave just like built-in types, sharing the familiar pattern of creating, combining, and passing values.
  • Complex numbers and infinite-precision integers resemble int, while vectors and strings resemble built-in arrays; the source also describes vectors and strings as better behaved than the arrays they resemble.
  • The shared part concerns how a type is used. Each concrete class keeps its own semantics and its own operations, so the same visible syntax can mean something different for a different class.
  • A built-in type is built from three ingredients: fundamental types, the const modifier, and declarator operators. C++ keeps these low-level and close to conventional hardware.
  • Abstraction mechanisms sit between the two layers, letting programmers build user-defined types (classes and enumerations) out of the built-in foundation.

Related concepts

More concepts starting with B