C++ Data types

When programming in a programming language, various variables are needed to store various kinds of information. A variable retains the memory location of the value it stores. This means that when you create a variable, some space is reserved in memory.

You may need to store information of various data types (such as character, wide character, integer, floating-point, double floating-point, boolean, etc.). The operating system will allocate memory based on the variable's data type and decide what to store in the reserved memory.

Basic built-in types

C++ provides programmers with a rich variety of built-in data types and user-defined data types. The following table lists seven basic C++ data types:

TypeKeywords
Boolean typebool
Character typechar
integerint
Floating-point typefloat
Double floating-point typedouble
Void void
Wide character type

wchar_t

In fact, wchar_t is derived like this:

typedef short int wchar_t;

Therefore, wchar_t actually occupies the same space as short int.

Some basic types can be modified with one or more type modifiers:

ModifiersDescriptionExample
signedIndicates signed type (default)signed int x = -10;
unsignedDenotes unsigned typeunsigned int y = 10;
shortDenotes a short integer typeshort int z = 100;
longDenotes a long integer typelong int a = 100000;
constIndicates constant, value cannot be modifiedconst int b = 5;
volatileIndicates that the variable may be modified unexpectedly, prohibiting compiler optimization.volatile int c = 10;
mutableIndicates class members can beconstModified in the objectmutable int counter;

The following table shows the memory required for various variable types when storing values in memory, as well as the maximum and minimum values that a variable of that type can store.

Note:There may be differences between different systems; one byte is 8 bits.

Note:By default, int, short, and long are signed.

Note:long int is 8 bytes, and int is always 4 bytes. Early C compilers defined long int as occupying 4 bytes and int as occupying 2 bytes. The newer C/C++ standards are compatible with this early setting.

Data typesDescriptionSize (bytes)Range/Value example
boolBoolean type, representing true or false1trueorfalse
charCharacter type, usually used to store ASCII characters.1-128 to 127 or 0 to 255
signed charSigned character type1-128 to 127
unsigned charUnsigned character type10 to 255
wchar_tWide character type, used to store Unicode characters.2 or 4Platform-dependent
char16_t16-bit Unicode character type (introduced in C++11)20 to 65,535
char32_t32-bit Unicode character type (introduced in C++11)40 to 4,294,967,295
shortshort integer2-32,768 to 32,767
unsigned shortUnsigned short integer20 to 65,535
intinteger4-2,147,483,648 to 2,147,483,647
unsigned intUnsigned integer type40 to 4,294,967,295
longlong integer4 or 8Platform-dependent
unsigned longUnsigned long integer4 or 8Platform-dependent
long longLong long integer (introduced in C++11)8-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
unsigned long longUnsigned long long integer (introduced in C++11)80 to 18,446,744,073,709,551,615
floatSingle-precision floating point4Approximately ±3.4e±38 (6-7 significant digits)
doubleDouble-precision floating point8Approximately ±1.7e±308 (15 significant digits)
long doubleExtended-precision floating point8, 12, or 16Platform-dependent

New types added in C++11

Data typesDescriptionExample
autoAutomatic type deductionauto x = 10;
decltypeObtain the type of an expressiondecltype(x) y = 20;
nullptrNull pointer constantint* ptr = nullptr;
std::initializer_listInitializer list typestd::initializer_list<int> list = {1, 2, 3};
std::tupleTuple type, which can store multiple values of different types.std::tuple<int, float, char> t(1, 2.0, 'a');

Note that the storage size of various types is related to the system bit width, but currently the mainstream is mainly 64-bit systems.

The following lists the differences in storage size between 32-bit systems and 64-bit systems (Windows is the same):

From the table above, it can be seen that the size of variables will vary depending on the compiler and the computer being used.

The following example will output the size of various data types on your computer.

Example

#include<iostream> #include <limits> using namespace std; int main() { cout << "type: \t\t" << "************size**************"<< endl; cout << "bool: \t\t" << "Number of bytes occupied:" << sizeof(bool); cout << "\Maximum value of t:" << (numeric_limits<bool>::max)(); cout << "\t\Minimum value of t:" << (numeric_limits<bool>::min)() << endl; cout << "char: \t\t" << "Number of bytes occupied:" << sizeof(char); cout << "\Maximum value of t:" << (numeric_limits<char>::max)(); cout << "\t\Minimum value of t:" << (numeric_limits<char>::min)() << endl; cout << "signed char: \t" << "Number of bytes occupied:" << sizeof(signed char); cout << "\Maximum value of t:" << (numeric_limits<signed char>::max)(); cout << "\t\Minimum value of t:" << (numeric_limits<signed char>::min)() << endl; cout << "unsigned char: \t" << "Number of bytes occupied:" << sizeof(unsigned char); cout << "\Maximum value of t:" << (numeric_limits<unsigned char>::max)(); cout << "\t\Minimum value of t:" << (numeric_limits<unsigned char>::min)() << endl; cout << "wchar_t: \t" << "Number of bytes occupied:" << sizeof(wchar_t); cout << "\Maximum value of t:" << (numeric_limits<wchar_t>::max)(); cout << "\t\Minimum value of t:" << (numeric_limits<wchar_t>::min)() << endl; cout << "short: \t\t" << "Number of bytes occupied:" << sizeof(short); cout << "\Maximum value of t:" << (numeric_limits<short>::max)(); cout << "\t\Minimum value of t:" << (numeric_limits<short>::min)() << endl; cout << "int: \t\t" << "Number of bytes occupied:" << sizeof(int); cout << "\Maximum value of t:" << (numeric_limits<int>::max)(); cout << "\Minimum value of t:" << (numeric_limits<int>::min)() << endl; cout << "unsigned: \t" << "Number of bytes occupied:" << sizeof(unsigned); cout << "\Maximum value of t:" << (numeric_limits<unsigned>::max)(); cout << "\Minimum value of t:" << (numeric_limits<unsigned>::min)() << endl; cout << "long: \t\t" << "Number of bytes occupied:" << sizeof(long); cout << "\Maximum value of t:" << (numeric_limits<long>::max)(); cout << "\Minimum value of t:" << (numeric_limits<long>::min)() << endl; cout << "unsigned long: \t" << "Number of bytes occupied:" << sizeof(unsigned long); cout << "\Maximum value of t:" << (numeric_limits<unsigned long>::max)(); cout << "\Minimum value of t:" << (numeric_limits<unsigned long>::min)() << endl; cout << "double: \t" << "Number of bytes occupied:" << sizeof(double); cout << "\Maximum value of t:" << (numeric_limits<double>::max)(); cout << "\Minimum value of t:" << (numeric_limits<double>::min)() << endl; cout << "long double: \t" << "Number of bytes occupied:" << sizeof(long double); cout << "\Maximum value of t:" << (numeric_limits<long double>::max)(); cout << "\Minimum value of t:" << (numeric_limits<long double>::min)() << endl; cout << "float: \t\t" << "Number of bytes occupied:" << sizeof(float); cout << "\Maximum value of t:" << (numeric_limits<float>::max)(); cout << "\Minimum value of t:" << (numeric_limits<float>::min)() << endl; cout << "size_t: \t" << "Number of bytes occupied:" << sizeof(size_t); cout << "\Maximum value of t:" << (numeric_limits<size_t>::max)(); cout << "\Minimum value of t:" << (numeric_limits<size_t>::min)() << endl; cout << "string: \t" << "Number of bytes occupied:" << sizeof(string) << endl; // << "\tMaximum value: " << (numeric_limits<string>::max)() << "\tMinimum value: " << (numeric_limits<string>::min)() << endl; cout << "type: \t\t" << "************size**************"<< endl; return 0; }

This example usesendl, this will insert a newline character after each line,<<Operators are used to pass multiple values to the screen,sizeof()The operator is used to obtain the size of various data types.

When the above code is compiled and executed, it will produce the following results, which may vary depending on the computer used:

type:         ************size**************
bool:         所占字节数:1    最大值:1        最小值:0
char:         所占字节数:1    最大值:        最小值:?
signed char:     所占字节数:1    最大值:        最小值:?
unsigned char:     所占字节数:1    最大值:?        最小值:
wchar_t:     所占字节数:4    最大值:2147483647        最小值:-2147483648
short:         所占字节数:2    最大值:32767        最小值:-32768
int:         所占字节数:4    最大值:2147483647    最小值:-2147483648
unsigned:     所占字节数:4    最大值:4294967295    最小值:0
long:         所占字节数:8    最大值:9223372036854775807    最小值:-9223372036854775808
unsigned long:     所占字节数:8    最大值:18446744073709551615    最小值:0
double:     所占字节数:8    最大值:1.79769e+308    最小值:2.22507e-308
long double:     所占字节数:16    最大值:1.18973e+4932    最小值:3.3621e-4932
float:         所占字节数:4    最大值:3.40282e+38    最小值:1.17549e-38
size_t:     所占字节数:8    最大值:18446744073709551615    最小值:0
string:     所占字节数:24
type:         ************size**************

Derived data types

Data typesDescriptionExample
ArrayA collection of elements of the same typeint arr[5] = {1, 2, 3, 4, 5};
PointerA type that stores the memory address of a variableint* ptr = &x;
ReferenceVariable aliasint& ref = x;
FunctionFunction type, representing the signature of a functionint func(int a, int b);
StructUser-defined data type, which can contain multiple members of different types.struct Point { int x; int y; };
ClassUser-defined data type, supporting encapsulation, inheritance, and polymorphism.class MyClass { ... };
UnionMultiple members share the same block of memoryunion Data { int i; float f; };
EnumA user-defined set of integer constantsenum Color { RED, GREEN, BLUE };

Type alias

AliasDescriptionExample
typedefDefine an alias for an existing typetypedef int MyInt;
usingDefine an alias for an existing type (introduced in C++11)using MyInt = int;

Standard library type

Data typesDescriptionExample
std::stringString typestd::string s = "Hello";
std::vectorDynamic Arraystd::vector<int> v = {1, 2, 3};
std::arrayFixed-size array (introduced in C++11)std::array<int, 3> a = {1, 2, 3};
std::pairA container that stores two valuesstd::pair<int, float> p(1, 2.0);
std::mapKey-value pair containerstd::map<int, std::string> m;
std::setUnique value setstd::set<int> s = {1, 2, 3};

typedef declaration

You can usetypedefGive a new name to an existing type. The following is the syntax for defining a new type using typedef:

typedef type newname; 

For example, the following statement tells the compiler that feet is another name for int:

typedef int feet;

Now, the following declaration is completely legal; it creates an integer variable distance:

feet distance;

Enumeration type

Enumeration type (enumeration) is a derived data type in C++, which is a collection of several enumeration constants defined by the user.

If a variable has only a few possible values, it can be defined as an enumeration type. The so-called "enumeration" means listing the values of the variable one by one, and the value of the variable can only be within the range of the listed values.

To create an enum, you need to use the keywordenum. The general form of an enum type is:

enum 枚举名{ 
     标识符[=整型常数], 
     标识符[=整型常数], 
... 
    标识符[=整型常数]
} 枚举变量;
    

If the enumeration is not initialized, i.e., when "= integer constant" is omitted, it starts from the first identifier.

For example, the following code defines a color enumeration, and the type of variable c is color. Finally, c is assigned the value "blue".

enum color { red, green, blue } c;
c = blue;

By default, the value of the first name is 0, the value of the second name is 1, the value of the third name is 2, and so on. However, you can also assign a special value to a name by simply adding an initial value. For example, in the following enumeration,greenThe value is 5.

enum color { red, green=5, blue };

Here,bluehas a value of 6, because by default, each name is 1 greater than the name before it, but the value of red is still 0.


Type conversion

Type conversion is the conversion of a value of one data type into a value of another data type.

There are four types of type conversion in C++: static conversion, dynamic conversion, const conversion, and reinterpret conversion.

Static Cast

Static conversion is the forced conversion of a value of one data type into a value of another data type.

Static conversion is usually used for conversions between objects of similar types, for example, converting an int type to a float type.

Static cast does not perform any runtime type checking, so it may lead to runtime errors.

Example

int i = 10; float f = static_cast<float>(i); // Statically convert int type to float type

Dynamic Cast

Dynamic conversion (dynamic_cast) is a mechanism in C++ used for downcasting in an inheritance hierarchy.

Dynamic conversion is usually used to convert a base class pointer or reference into a derived class pointer or reference.

Dynamic cast performs type checking at runtime. If the conversion fails, it returns nullptr for pointer types, and throws a std::bad_cast exception for reference types.

Syntax:

dynamic_cast<目标类型>(表达式)
  • Target type: Must be a pointer or reference type.

  • Expression: The base class pointer or reference that needs to be converted.

Example: Dynamic cast of pointer types

#include <iostream> class Base { public: virtual ~Base() = default; // The base class must have virtual functions }; class Derived : public Base { public: void show() { std::cout << "Derived class method" << std::endl; } }; int main() { Base* ptr_base = new Derived; // Base class pointer points to derived class object // Convert base class pointer to derived class pointer Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base); if (ptr_derived) { ptr_derived->show(); // Conversion successful, call derived class method } else { std::cout << "Dynamic cast failed!" << std::endl; } delete ptr_base; return 0; }

Output:

Derived class method

Example: Dynamic cast of reference types

#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() = default; // The base class must have virtual functions
};

class Derived : public Base {
public:
    void show() {
        std::cout << "Derived class method" << std::endl;
    }
};

int main() {
    Derived derived_obj;
    Base& ref_base = derived_obj; // Base class reference bound to derived class object

    try {
        // Convert base class reference to derived class reference
        Derived& ref_derived = dynamic_cast<Derived&>(ref_base);
        ref_derived.show(); // Conversion successful, call derived class method
    } catch (const std::bad_cast& e) {
        std::cout << "Dynamic cast failed: " << e.what() << std::endl;
    }

    return 0;
}

Output:

Derived class method
FeaturesPointer typeReference type
Return value on conversion failurereturnnullptrThrowstd::bad_castException
Applicable scenariosDowncasting, runtime type checkingDowncasting, runtime type checking
Performance overheadHigherHigher
Base class requirementMust have virtual functionsMust have virtual functions

Const Cast

Const conversion is used to convert an object of const type into an object of non-const type.

Const conversion can only be used to cast away the const attribute; it cannot change the type of the object.

Example

const int i = 10; int& r = const_cast<int&>(i); // const_cast, convert const int to int

Reinterpret Cast

Reinterpret conversion reinterprets a value of one data type as a value of another data type, usually used for conversions between different data types.

Reinterpret conversion does not perform any type checking, which may lead to undefined behavior.

Example

int i = 10; float f = reinterpret_cast<float&>(i); // reinterpret_cast int type to float type
other extensions