Fundamental Data Types

The fundamental types in C++ include integer types, character types, and floating-point types. These types are considered fundamental because they are built into the language itself and can be used to create more complex data structures and objects. Additionally, they are the building blocks for other C++ data types, such as arrays, structures, and classes.

The following table lists the type specifiers of the fundamental data types in C++.

Character TypesInteger TypesFloating-Point Types
charboolfloat
wchar_tshortdouble
char16_tintlong double
char32_tlong
char8_tlong long
unsigned short
unsigned int
unsigned long
unsigned long long
signed char
unsigned char

void

void is considered a fundamental type in C++. It represents the absence of a value and is used as a placeholder in function signatures and pointer declarations. It cannot be used to declare variables because it has no size or storage, but it is an important part of the C++ language and is often used in conjunction with other data types.

bool

bool is considered an integer type in C++, but it is often treated as a separate category due to its Boolean semantics.

signed char and unsigned char

In C++, the char type is considered a distinct type that can be used to represent individual characters in text string. It is technically not considered an integer type, but does have an integer representation according to the ASCII or Unicode standard, which allows it to be used for integer calculations in some context.

When signed or unsigned is applied to char, it creates a type for small integers that can hold values between 0 and 255 (or -128 to 127 in the case of signed char).Therefore, signed char and unsigned char are both considered integer types.

Note that char is a distinct type from signed char and unsigned char, and it is not guaranteed to be signed or unsigned. The signedness of char is implementation-defined, and it can vary depending on the platform and the compiler.

Type qualifiers and cv-correctness

Type specifiers can be combined with type qualifiers. In C++, there are two type qualifiers: const and volatile.

  • const indicates that a variable's value cannot be modified after it has been initialized.
  • volatile indicates that a variable's value can be modified by external factors such as hardware or other processes. Sometimes, volatile is applied to a variable to prevent compiler optimization.

CV-correctness is a programming concept in C++ that involves using the const and volatile type qualifiers to ensure that functions and data members behave correctly in the presence of const and volatile objects.

For example, a member function that does not modify the state of the object it operates on should be declared const. This ensures that the function can be called on const objects, and that it does not modify the state of the object.

class Example {
public:
    // Declared const because it does not modify the object state
    int getValue() const; 
private:
    int value_;
};

int Example::getValue() const {
    return value_;
}

A member variable can also be declared const if it should not be modified in any case:

class Example {
public:
    Example(int value) : value_(value) {}
    int getValue() const {
        // Cannot be modified because getValue is const
        return value_; 
    }
private:
    // Declared const to ensure it cannot be modified
    const int value_; 
};

The volatile qualifier can be applied to variables that can be changed by external factors, such as hardware or other processes. This ensures that the compiler does not optimize away accesses to the variable, which could cause incorrect behavior.

volatile int* ptr; // Pointer to a volatile int

Using CV-correctness can help prevent errors and improve code safety by ensuring that functions and data members behave correctly in the presence of const and volatile objects.

mutable

In C++, mutable is a type specifier that can be used to declare a non-static data member that can be modified even if the containing object is declared const. This is useful when the variable represents a cache or temporary value that does not affect the state of the object.

class Example {
public:
    int getValue() const {
        // Marked const, so it cannot modify any non-mutable members.
        // However, it can modify mutable members such as cachedValue_.
        if (cachedValue_ == 0) {
            cachedValue_ = someExpensiveCalculation();
        }
        return cachedValue_;
    }

private:
    // Declared mutable to allow modification even 
    // if Example object is const
    mutable int cachedValue_;
};

In this example, cachedValue_ is declared as mutable, which allows it to be modified even if the containing object is declared const. The getValue() function is declared const, which means it cannot modify any non-mutable members of the Example object, but it can modify the mutable member cachedValue_.