この章では、C++の変数とデータ型について学んでいきます
変数
C言語ではブロック({}で囲まれた部分)内で宣言された変数は、そのブロックの先頭で宣言される必要がありました
C++では、ブロック内で宣言された変数は、その宣言された時点からそのブロックの終わりまでがスコープとなり、ブロックの途中で宣言することも可能になりました
変数名は、アルファベットの大文字、小文字、数字、およびアンダースコア(_)の組み合わせで、命名することができます
ただし、数字で始まるものや数字だけのものは、変数名にすることはできません
また、C++で定義された予約語を変数名に使用することもできません
変数宣言の構文は以下の通りです
データ型 変数名;変数を宣言した直後、変数の値はどんな値か不定のため、変数宣言と同時に変数の初期化を行ったり、値を代入する必要があります
変数の初期化や代入をする例を以下に示します
int a(0);
int b = 1;
int a = 0, b, c=2; // aを0で、cを2で初期化しbは初期化しない
int x;
x = 5; // xに5を代入データ型
C++のデータ型は、変数が格納できる情報の種類とサイズを定めるものです
データ型によって、変数が占有するメモリ量や表現できる値の範囲が決定されます
また、そのデータ型に応じて適用可能な操作や演算の種類も決まります
適切なデータ型を選択することで、プログラムの効率性と正確性を向上させることができます
C++には、以下のようなデータ型があります
- 基本データ型
C++にあらかじめ組み込まれているデータ型で、整数 (int)、文字 (char)、真偽値 (bool)、浮動小数点数 (float, double) などを扱います
型の種類や有効範囲などは以下のURLを参考にしてください
参考:C++ の組み込み演算子、優先順位、結合規則 | Microsoft Learn
いくつかのデータ型を使用したサンプルプログラムを示します
// int型は整数を表すデータ型です
int x = 10; // xは10という整数を格納します
int y = -5; // yは-5という整数を格納します
// char型は文字を表すデータ型です
char c = ‘A’; // cは’A’という文字を格納します
char d = ‘9’; // dは’9’という文字を格納します
// bool型は真偽値を表すデータ型です
bool b = true; // bはtrueという真偽値を格納します
bool f = false; // fはfalseという真偽値を格納します
// float型は単精度浮動小数点数を表すデータ型です
float pi = 3.14f; // piは3.14という浮動小数点数を格納します
float e = 2.71f; // eは2.71という浮動小数点数を格納します
// double型は倍精度浮動小数点数を表すデータ型です
double g = 9.8; // gは9.8という浮動小数点数を格納します
double h = 6.63e-34; // hは6.63×10^-34^という浮動小数点数を格納します- 派生データ型
基本データ型を基に構成されるデータ型で、関数 (void(int))、配列 (char[])、ポインタ (int*)、参照 (int& など) があります
- ユーザー定義データ型
プログラマーが独自に定義するデータ型で、クラス、構造体 、共用体、列挙型 などが含まれます
- 型推論(C++ 11)
C++ 11から、型推論という機能が搭載されました
変数の宣言時に初期値を与えているとき、初期値の型を使って変数を宣言するようにコンパイラに指示する機能のことです
以下のように以下のように記述します
auto 変数名 = 初期値;auto型という型があるわけではなく、コンパイラに型推論を指示するためだけの特別な予約語になっています
auto d = 3.14; // dはdouble型に推論されます型変換
「型変換」とは、変数のデータ型を違うデータ型に変換することです
型変換には、「暗黙的型変換」と「明示的型変換」があります
暗黙的型変換
暗黙的型変換は、代入や演算式の中で、コンパイラが自動的に行う型変換のことで、主に以下の場面で見られます
① 異なる型への代入時
例えば、double型の値をint型の変数に代入する場合や、intからunsigned intへの代入、unsigned intからunsigned shortへの代入などが該当します
この際、情報が失われる可能性があることに注意が必要です
特に、浮動小数点数を整数型に変換する場合は小数部分が切り捨てられ、より大きな整数型からより小さな整数型への変換では、値が範囲外の場合に予期せぬ結果を招くことがあります
② 異なるデータ型が混在する演算時
演算を行う際、異なるデータ型の変数が組み合わされると、より広い範囲またはより高精度のデータ型に自動的に変換されます
例えば、int型とdouble型の変数が加算される場合、int型がdouble型に変換されてから演算が行われます
明示的型変換
明示的型変換は、プログラマーが意図的に型変換を行うことを指定する方法です。C++では、キャスト演算子を用いて記述します
castの種類<型名>(変数または値)C++には、目的と安全性に応じていくつかの種類のキャスト演算子が用意されています
- static_cast: コンパイル時に型チェックが行われる、最も一般的なキャストです
互換性のある型間の変換や、暗黙的な変換では行われない型変換(例えば、void*から特定の型への変換など)に使用できます
ただし、実行時の型チェックは行われないため、不適切なキャストは未定義動作を引き起こす可能性があります - dynamic_cast: 実行時に型変換の安全性をチェックするキャストです
主にクラスの継承関係におけるダウンキャスト(派生クラスへのキャスト)に使用され、キャストが安全でない場合はヌルポインタ(ポインタの場合)または例外(参照の場合)を返します - const_cast: 変数のconst修飾子やvolatile修飾子を取り除く(または付加する)ために使用します
constを取り除く操作は、constではない関数にconstな変数を渡す必要があるなど、限定的な状況でのみ使用すべきであり、安易な使用は避けるべきです - reinterpret_cast: 型のビットパターンを異なる型として再解釈するための、最も強力で危険なキャストです
コンパイラによるチェックはほとんど行われず、移植性も低いため、特殊な低レベルプログラミング以外での使用は推奨されません
以下に、static_castを使用したサンプルプログラムを示します
char c = 30;
int n = static_cast<int>(c);
double f = 1.51;
int num = static_cast<int>(f);予約語
C++における予約語とは、言語仕様によって特別な意味を持つ単語であり、変数名や関数名などの識別子として使用することはできません
予約語は、C++の構文や機能を記述するために不可欠な要素です
C++の予約語は、その由来や役割によっていくつかのカテゴリに分類できます
- C言語から継承された予約語
if、while、return など、C言語にも存在する予約語です - C++で新たに追加された予約語
class、template、bool など、C++で導入された予約語です - 演算子の代替となる予約語
and (論理積)、or (論理和)、not (否定) など、演算子と同じ意味を持つ予約語です - C++のバージョンによって導入された予約語
constexpr (C++11)、auto (C++11)、nullptr (C++11) など、新しい規格で追加された予約語です - プリプロセッサで使用される予約語
#include、#define、#ifdefなど、コンパイル前処理を行うプリプロセッサの指令です
予約語とは別に、C++の標準ライブラリやヘッダファイルには、あらかじめ定義された識別子も存在します
これらの識別子は予約語とは異なり、再定義やオーバーロードが可能ですが、予期せぬエラーや混乱を避けるため、同じ名前の使用は推奨されません
事前に定義された識別子の例としては、以下のようなものがあります
- main関数
プログラムの実行を開始する特別な関数です - cin, cout などのストリームオブジェクト
標準的な入出力操作を行うためのオブジェクトです - string, vector などのクラスやテンプレート
文字列や動的配列といったデータ構造を扱うための型です - endl, setprecision などのマニピュレータ
出力ストリームの書式を制御するための機能です - std, iostream などの名前空間やヘッダファイル
標準ライブラリの機能や宣言をまとめたものです
より詳細な情報については、以下のリファレンスを参照してください
C++ のキーワード – cppreference.com
定数
C++における定数とは、プログラムの実行中に値が変化しない固定された値を指します
定数を使用することで、プログラムの可読性と保守性を高めることができます
定数には、リテラルと名前付き定数の2種類があります
リテラル
リテラルは、ソースコードに直接記述された値そのものです
整数 (75)、浮動小数点数 (75.0)、文字 (‘A’)、文字列 (“Hello”)、真偽値 (true, false)、ポインタ (nullptr) など、様々な型のリテラルが存在します
また、u (unsigned)、l (long)、f (float) などの接尾辞を用いることで、リテラルの型を明示的に指定することも可能です
例:
・75 (int型)
・75u (unsigned int型)
・75l (long型)
・75.0f (float型)
・75.0 (double型)
名前付き定数
名前付き定数とは、リテラルに識別子(名前)を付けたもので、const キーワードを用いて宣言します
const double PI = 3.14; // PIという名前のdouble型定数を定義し、3.14で初期化名前付き定数は、宣言と同時に初期化する必要があり、宣言後に値を変更することはできません
名前付き定数を使用することで、プログラム内で特定の値を一貫して参照でき、意味のある名前によって可読性も向上します
例えば、以下のコードでは、PIという名前付き定数を使って円の面積を計算しています
const double PI = 3.14; // PIという名前の定数を作る
int radius = 4; // 半径を4にする
double area = PI * radius * radius; // 面積を計算する演算子
C++における演算子とは、何らかの計算や操作を行うための記号です
例えば、+は加算、-は減算、*は乗算、/は除算、%は剰余、=は代入などの演算子があります
演算子は、オペランドと呼ばれる値や変数に対して作用します
例えば、a + bという式では、+が演算子で、aとbがオペランドです
演算子には、優先順位と結合性という概念があります
優先順位とは、複数の演算子がある場合に、どの演算子を先に評価するかを決めるルールです
結合性とは、同じ優先順位の演算子がある場合に、どの方向から評価するかを決めるルールです
例えば、a + b * cという式では、*が+よりも優先順位が高いので、まずb * cを評価しますa * b / cという式では、*と/が同じ優先順位で、左から右に結合するので、まずa * bを評価します
演算子の優先順位や結合性は、C++の演算子の優先順位 – cppreference.comの表で確認できます
C++には、算術演算子、代入演算子、比較演算子、論理演算子、ビット演算子、単項演算子、条件演算子、コンマ演算子、キャスト演算子、sizeof演算子、new/delete演算子、関数呼び出し演算子、メンバアクセス演算子、配列添え字演算子、ポインタ演算子、参照演算子、スコープ演算子、型演算子など、様々な種類の演算子があります
- 算術演算子: 四則演算や剰余など、数値を扱う演算子 (
+,-,*,/,%) - 代入演算子: 変数に値を代入する演算子 (
=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=) - 比較演算子: 値の大小や等価性を比較する演算子 (
==,!=,>,<,>=,<=) - 論理演算子: 真偽値を組み合わせる演算子 (
&&(AND),||(OR),!(NOT)) - ビット演算子: ビット単位で演算を行う演算子 (
&,|,^,~,<<,>>) - 単項演算子: 一つのオペランドに対して作用する演算子 (
++,--,+,-,!,~,*(間接参照),&(アドレス取得)) - 条件演算子: 条件に基づいて異なる値を返す演算子 (
?:) - コンマ演算子: 複数の式を順に評価する演算子 (
,) - キャスト演算子: 変数の型を明示的に変換する演算子 (
static_cast,dynamic_cast,reinterpret_cast,const_cast) sizeof演算子: オペランドのサイズをバイト単位で取得する演算子 (sizeof)new/delete演算子: 動的にメモリを確保・解放する演算子 (new,new[],delete,delete[])- 関数呼び出し演算子: 関数を呼び出す際に使用する演算子 (
()) - メンバアクセス演算子: クラスや構造体のメンバにアクセスする演算子 (
.,->) - 配列添え字演算子: 配列の要素にアクセスする演算子 (
[]) - ポインタ演算子: ポインタを操作する演算子 (
*(間接参照),&(アドレス取得),->) - 参照演算子: 変数の別名を作成する際に使用する演算子 (
&) - スコープ解決演算子: 名前空間やクラスのメンバにアクセスする演算子 (
::) - 型演算子: 型に関する情報を取得する演算子 (
typeid)
それぞれの演算子の意味や使い方は、演算子オーバーロード – cppreference.comのページをご確認ください
以下に、C++の演算子の例を5つ示します
コードブロック内のコメントは、演算子の種類や結果を説明しています
#include <iostream>
using namespace std;
int main() {
int a = 10; // 代入演算子
int b = 20;
int c = a + b; // 算術演算子
cout << c << endl; // 関数呼び出し演算子とメンバアクセス演算子
// 出力: 30
bool d = a > b; // 比較演算子
cout << d << endl;
// 出力: 0 (false)
bool e = a < b && b < 30; // 論理演算子
cout << e << endl;
// 出力: 1 (true)
int f = a << 2; // ビット演算子
cout << f << endl;
// 出力: 40 (aのビットを左に2つずらす)
int g = a > b ? a : b; // 条件演算子
cout << g << endl;
// 出力: 20 (aとbのうち大きい方を返す)
}using namespace std;
usin namespaceは指定された名前のネームスペースを使うことを意味しています
このように記述することにより、名前空間stdを使用すると定義しています
この定義により、coutやendlを使用する場合、std::を省略して使用することができるようになります
コメント