C++ データ型

プログラミング言語を使用してプログラミングを行う際には、さまざまな情報を格納するためにさまざまな変数を使用する必要があります。変数は、格納されている値のメモリ位置を保持します。つまり、変数を作成すると、メモリ内にいくつかの領域が確保されます。

さまざまなデータ型(文字型、ワイド文字型、整数型、浮動小数点型、倍精度浮動小数点型、ブール型など)の情報を格納する必要があるかもしれません。オペレーティングシステムは、変数のデータ型に基づいてメモリを割り当て、確保されたメモリに何を格納するかを決定します。

基本的な組み込み型

C++ は、プログラマに豊富な組み込みデータ型とユーザー定義データ型を提供します。次の表は、7つの基本的な C++ データ型を示しています。

型キーワード
ブール型bool
文字型char
整数型int
浮動小数点型float
倍精度浮動小数点型double
無型 void
ワイド文字型

wchar_t

実際、wchar_t は次のように由来しています:

typedef short int wchar_t;

したがって、wchar_t の実際のサイズは short int と同じです。

一部の基本型は、1つ以上の型修飾子を使用して修飾できます。

修飾子説明例
signed符号付き型を表します(デフォルト)signed int x = -10;
unsigned符号なし型を表しますunsigned int y = 10;
short短整数型を表しますshort int z = 100;
long長整数型を表しますlong int a = 100000;
const定数を表し、値を変更できませんconst int b = 5;
volatile変数が予期せず変更される可能性があることを示し、コンパイラの最適化を禁止しますvolatile int c = 10;
mutableクラスメンバーがオブジェクト内でconst変更できることを示しますmutable int counter;

次の表は、さまざまな変数型がメモリに値を格納する際に必要なメモリ容量と、その型の変数が格納できる最大値と最小値を示しています。

注意:システムによって異なる場合があります。1バイトは8ビットです。

注意:デフォルトでは、int、short、long はすべて符号付き(signed)です。

注意:long int は8バイト、int はすべて4バイトです。初期の C コンパイラでは long int が4バイト、int が2バイトと定義されていましたが、新しい C/C++ 標準はこの初期の設定と互換性があります。

データ型説明サイズ(バイト)範囲/値の例
boolブール型。真または偽を表します1true 或 false
char文字型。通常、ASCII 文字を格納するために使用されます1-128 から 127 または 0 から 255
signed char符号付き文字型1-128 から 127
unsigned char符号なし文字型10 から 255
wchar_tワイド文字型。Unicode 文字を格納するために使用されます2 または 4プラットフォームに依存します
char16_t16ビット Unicode 文字型(C++11 で導入)20 から 65,535
char32_t32ビット Unicode 文字型(C++11 で導入)40 から 4,294,967,295
short短整数型2-32,768 から 32,767
unsigned short符号なし短整数型20 から 65,535
int整数型4-2,147,483,648 から 2,147,483,647
unsigned int符号なし整数型40 から 4,294,967,295
long長整数型4 または 8プラットフォームに依存します
unsigned long符号なし長整数型4 または 8プラットフォームに依存します
long long長長整数型(C++11 で導入)8-9,223,372,036,854,775,808 から 9,223,372,036,854,775,807
unsigned long long符号なし長長整数型(C++11 で導入)80 から 18,446,744,073,709,551,615
float単精度浮動小数点数4約 ±3.4e±38(6〜7桁の有効数字)
double倍精度浮動小数点数8約 ±1.7e±308(15桁の有効数字)
long double拡張精度浮動小数点数8、12、または16プラットフォームに依存します

C++11 で追加された型

データ型説明例
auto自動型推論auto x = 10;
decltype式の型を取得しますdecltype(x) y = 20;
nullptrヌルポインタ定数int* ptr = nullptr;
std::initializer_list初期化リスト型std::initializer_list<int> list = {1, 2, 3};
std::tupleタプル型。複数の異なる型の値を格納できますstd::tuple<int, float, char> t(1, 2.0, 'a');

注意:さまざまな型の記憶域サイズはシステムのビット数に関係しますが、現在一般的に使用されているのは64ビットシステムが主流です。

以下に、32ビットシステムと64ビットシステムの記憶域サイズの違いを示します(Windows では同じ):

上の表からわかるように、変数のサイズはコンパイラや使用するコンピュータによって異なります。

次の例では、お使いのコンピュータ上のさまざまなデータ型のサイズを出力します。

例

#include<iostream> #include <limits> using namespace std; int main() { cout << "type: \t\t" << "************size**************"<< endl; cout << "bool: \t\t" << "占有バイト数:" << sizeof(bool); cout << "\t最大値:" << (numeric_limits<bool>::max)(); cout << "\t\t最小値:" << (numeric_limits<bool>::min)() << endl; cout << "char: \t\t" << "占有バイト数:" << sizeof(char); cout << "\t最大値:" << (numeric_limits<char>::max)(); cout << "\t\t最小値:" << (numeric_limits<char>::min)() << endl; cout << "signed char: \t" << "占有バイト数:" << sizeof(signed char); cout << "\t最大値:" << (numeric_limits<signed char>::max)(); cout << "\t\t最小値:" << (numeric_limits<signed char>::min)() << endl; cout << "unsigned char: \t" << "占有バイト数:" << sizeof(unsigned char); cout << "\t最大値:" << (numeric_limits<unsigned char>::max)(); cout << "\t\t最小値:" << (numeric_limits<unsigned char>::min)() << endl; cout << "wchar_t: \t" << "占有バイト数:" << sizeof(wchar_t); cout << "\t最大値:" << (numeric_limits<wchar_t>::max)(); cout << "\t\t最小値:" << (numeric_limits<wchar_t>::min)() << endl; cout << "short: \t\t" << "占有バイト数:" << sizeof(short); cout << "\t最大値:" << (numeric_limits<short>::max)(); cout << "\t\t最小値:" << (numeric_limits<short>::min)() << endl; cout << "int: \t\t" << "占有バイト数:" << sizeof(int); cout << "\t最大値:" << (numeric_limits<int>::max)(); cout << "\t最小値:" << (numeric_limits<int>::min)() << endl; cout << "unsigned: \t" << "占有バイト数:" << sizeof(unsigned); cout << "\t最大値:" << (numeric_limits<unsigned>::max)(); cout << "\t最小値:" << (numeric_limits<unsigned>::min)() << endl; cout << "long: \t\t" << "占有バイト数:" << sizeof(long); cout << "\t最大値:" << (numeric_limits<long>::max)(); cout << "\t最小値:" << (numeric_limits<long>::min)() << endl; cout << "unsigned long: \t" << "占有バイト数:" << sizeof(unsigned long); cout << "\t最大値:" << (numeric_limits<unsigned long>::max)(); cout << "\t最小値:" << (numeric_limits<unsigned long>::min)() << endl; cout << "double: \t" << "占有バイト数:" << sizeof(double); cout << "\t最大値:" << (numeric_limits<double>::max)(); cout << "\t最小値:" << (numeric_limits<double>::min)() << endl; cout << "long double: \t" << "占有バイト数:" << sizeof(long double); cout << "\t最大値:" << (numeric_limits<long double>::max)(); cout << "\t最小値:" << (numeric_limits<long double>::min)() << endl; cout << "float: \t\t" << "占有バイト数:" << sizeof(float); cout << "\t最大値:" << (numeric_limits<float>::max)(); cout << "\t最小値:" << (numeric_limits<float>::min)() << endl; cout << "size_t: \t" << "占有バイト数:" << sizeof(size_t); cout << "\t最大値:" << (numeric_limits<size_t>::max)(); cout << "\t最小値:" << (numeric_limits<size_t>::min)() << endl; cout << "string: \t" << "占有バイト数:" << sizeof(string) << endl; // << "\t最大值:" << (numeric_limits<string>::max)() << "\t最小值:" << (numeric_limits<string>::min)() << endl; cout << "type: \t\t" << "************size**************"<< endl; return 0; }

この例では、endl を使用しています。endlこれは、各行の後に改行を挿入します。<<演算子は、複数の値を画面に出力するために使用されます。sizeof()演算子は、さまざまなデータ型のサイズを取得するために使用されます。

上記のコードをコンパイルして実行すると、次の結果が生成されます。結果は使用するコンピュータによって異なります。

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**************

派生データ型

データ型説明例
配列同じ型の要素のコレクションint arr[5] = {1, 2, 3, 4, 5};
ポインタ変数のメモリアドレスを格納する型int* ptr = &x;
参照変数の別名int& ref = x;
関数関数型。関数のシグネチャを表しますint func(int a, int b);
構造体ユーザー定義のデータ型。複数の異なる型のメンバーを含むことができますstruct Point { int x; int y; };
クラスユーザー定義のデータ型。カプセル化、継承、ポリモーフィズムをサポートしますclass MyClass { ... };
共用体複数のメンバーが同じメモリブロックを共有しますunion Data { int i; float f; };
列挙型ユーザー定義の整数定数集合enum Color { RED, GREEN, BLUE };

型エイリアス

エイリアス説明例
typedef既存の型にエイリアスを定義するtypedef int MyInt;
using既存の型にエイリアスを定義する(C++11で導入)using MyInt = int;

標準ライブラリ型

データ型説明例
std::string文字列型std::string s = "Hello";
std::vector動的配列std::vector<int> v = {1, 2, 3};
std::array固定サイズ配列(C++11で導入)std::array<int, 3> a = {1, 2, 3};
std::pair2つの値を格納するコンテナstd::pair<int, float> p(1, 2.0);
std::mapキーと値のペアのコンテナstd::map<int, std::string> m;
std::set一意な値の集合std::set<int> s = {1, 2, 3};

typedef 宣言

あなたは使用できますtypedef既存の型に新しい名前を付けることができます。以下はtypedefを使用して新しい型を定義する構文です:

typedef type newname; 

例えば、次の文はコンパイラにfeetがintの別名であることを伝えます:

typedef int feet;

これで、次の宣言は完全に合法であり、整数型変数distanceを作成します:

feet distance;

列挙型

列挙型(enumeration)はC++における派生データ型の一種で、ユーザーが定義した複数の列挙定数の集合です。

変数がわずか数種類の可能な値しか持たない場合、列挙(enumeration)型として定義できます。「列挙」とは変数の値を一つずつ列挙することを指し、変数の値は列挙された値の範囲内に限定されます。

列挙を作成するには、キーワードが必要ですenum。列挙型の一般的な形式は次のとおりです:

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

列挙が初期化されていない場合、つまり「=整数定数」を省略した場合、最初の識別子から始まります。

例えば、次のコードは色の列挙を定義し、変数cの型はcolorです。最後に、cには"blue"が代入されます。

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

デフォルトでは、最初の名前の値は0、2番目の名前の値は1、3番目の名前の値は2、というようになります。ただし、初期値を追加するだけで、名前に特別な値を与えることもできます。例えば、次の列挙では、greenの値は5です。

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

ここでは、blueの値は6です。デフォルトでは、各名前は前の名前より1大きくなりますが、redの値は依然として0です。


型変換

型変換とは、あるデータ型の値を別のデータ型の値に変換することです。

C++には4つの型変換があります:静的変換、動的変換、定数変換、再解釈変換です。

静的キャスト(Static Cast)

静的変換は、あるデータ型の値を別のデータ型の値に強制変換することです。

静的変換は通常、型が類似したオブジェクト間の変換に使用されます。例えば、int型をfloat型に変換する場合です。

静的変換は実行時の型チェックを行わないため、実行時エラーを引き起こす可能性があります。

例

int i = 10; float f = static_cast<float>(i); // int型をfloat型に静的に変換

動的キャスト(Dynamic Cast)

動的変換(dynamic_cast)は、C++で継承階層内でダウンキャスト(downcasting)を行うためのメカニズムです。

動的変換は通常、基底クラスポインタまたは参照を派生クラスポインタまたは参照に変換するために使用されます。

動的変換は実行時に型チェックを行います。変換に失敗した場合、ポインタ型にはnullptrが返され、参照型にはstd::bad_cast例外がスローされます。

構文:

dynamic_cast<目标类型>(表达式)
  • ターゲット型:ポインタ型または参照型である必要があります。

  • 式:変換する必要がある基底クラスポインタまたは参照です。

例:ポインタ型の動的キャスト

#include <iostream> class Base { public: virtual ~Base() = default; // 基底クラスには仮想関数が必要 }; class Derived : public Base { public: void show() { std::cout << "Derived class method" << std::endl; } }; int main() { Base* ptr_base = new Derived; // 基底クラスポインタが派生クラスオブジェクトを指す // 基底クラスポインタを派生クラスポインタに変換 Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base); if (ptr_derived) { ptr_derived->show(); // 変換成功、派生クラスのメソッドを呼び出す } else { std::cout << "Dynamic cast failed!" << std::endl; } delete ptr_base; return 0; }

出力:

Derived class method

例:参照型の動的キャスト

#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() = default; // 基底クラスには仮想関数が必要
};

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

int main() {
    Derived derived_obj;
    Base& ref_base = derived_obj; // 基底クラス参照が派生クラスオブジェクトにバインド

    try {
        // 基底クラス参照を派生クラス参照に変換
        Derived& ref_derived = dynamic_cast<Derived&>(ref_base);
        ref_derived.show(); // 変換成功、派生クラスのメソッドを呼び出す
    } catch (const std::bad_cast& e) {
        std::cout << "Dynamic cast failed: " << e.what() << std::endl;
    }

    return 0;
}

出力:

Derived class method
特徴ポインタ型参照型
変換失敗時の戻り値返すnullptrスローするstd::bad_cast例外
適用シーンダウンキャスト、実行時型チェックダウンキャスト、実行時型チェック
パフォーマンスオーバーヘッド高い高い
基底クラスの要件仮想関数が必要仮想関数が必要

定数キャスト(Const Cast)

定数変換は、const型のオブジェクトを非const型のオブジェクトに変換するために使用されます。

定数変換はconst属性を取り除くためにのみ使用でき、オブジェクトの型を変更することはできません。

例

const int i = 10; int& r = const_cast<int&>(i); // 定数変換、const intをintに変換

再解釈キャスト(Reinterpret Cast)

再解釈変換は、あるデータ型の値を別のデータ型の値として再解釈します。通常、異なるデータ型間の変換に使用されます。

再解釈変換は型チェックを一切行わないため、未定義の動作を引き起こす可能性があります。

例

int i = 10; float f = reinterpret_cast<float&>(i); // int型をfloat型に再解釈変換
その他の拡張