C++
 Computer >> コンピューター >  >> プログラミング >> C++

static const vs #define vs enum?C++における定数定義方法の違いと使い分け

「static const」とは

「static const」は、static(記憶クラス指定子)とconst(型修飾子)を組み合わせたものです。

staticは変数の寿命とアクセス範囲を決定します。変数をstatic付きで宣言すると、プログラムが実行されている間ずっとメモリ上に保持されます。一方、通常の自動変数(auto変数)は、その変数が定義された関数の実行が終了すると破棄されます。

constは型修飾子の一種で、型システムを通じて値に関する追加情報を表現するために使われます。const修飾子を使って初期化された変数は、それ以降の値の変更を受け付けません。

つまり、static constで宣言・初期化された変数は、「プログラムの実行中ずっと値を保持し続け、かつ一切の変更を許さない」という特性を持つことになります。

サンプルコード

#include<iostream>
using namespace std;
int main(){
int input = 10;
static const int value = 5;
input += value;
cout << input;
return 0;
}

「#define」とは

プリプロセッサへの命令は「ディレクティブ」と呼ばれ、シャープ記号(#)で始まります。#の前には空白を置いてはならず、行末にセミコロンも不要です。

プリプロセス段階で行える主な処理には、以下のようなものがあります。

  • #includeディレクティブによる他ファイルの読み込み

  • #defineディレクティブによるシンボル定数やマクロの定義

また、一部のプリプロセッサディレクティブを使えば、条件に応じてコンパイル内容や他のディレクティブの実行を制御することも可能です。

補足:C++プログラムのプリプロセスは、コンパイルよりも前の段階で行われます。C++プリプロセッサは、ソースコードがコンパイルされる前に実行されるプログラムです。

#includeディレクティブで必要なヘッダーファイルを読み込む方法はすでに学んだ通りです。ここでは、#defineディレクティブに焦点を当てて解説します。

#defineディレクティブを使うと、シンボル名や定数を定義できます。例えば、次のように書きます。

#define PI 3.14159

この記述により、プログラム内に現れるPIはすべて3.14159に置き換えられます。

C++ #defineの使用例

次に完全なサンプルを考えてみましょう。PIと書かれた箇所はすべて、#defineディレクティブで定義した値3.14159に置き換わります。

Input: PI 3.14159
Output: Area of Circle 314.15

サンプルコード

#include<iostream>
using namespace std;
#define PI 3.14159
int main() {
   int r = 10;
   float cir;
   cir = PI * (r * r);
   cout<<"Area of Circle: "<<cir<<endl;
}

「enum」とは

enum(列挙型)はユーザー定義のデータ型で、変数が取り得る値の集合をあらかじめ定義しておき、その変数は限られた候補の中から1つの値しか取れないようにする仕組みです。enumキーワードを使って列挙型を定義します。

enum direction {East, West, North, South}dir;

この場合、列挙型の名前はdirectionであり、この型の変数は指定された4つの値のうちいずれか1つしか取れません。宣言の末尾にあるdirがenum変数です。

簡単な例で挙動を確認してみましょう。

ここではenum変数dirにWestを代入し、その値を表示すると「1」が出力されます。これは、enumの各要素にはデフォルトで0から順番に整数値が割り当てられるためです。つまりEast=0、West=1、North=2、South=3となります。

Input: direction {East, West, North, South} dir=West
Output: 1

サンプルコード

#include<iostream>
using namespace std;
enum direction {East, West, North, South} dir;
int main(){
   dir = West;
   cout<<dir;
   return 0;
}

enum変数のもう一つの宣言方法

先ほどの例では、enumの宣言時に同時に変数dirを宣言しましたが、enum変数は宣言を分けて定義することもできます。

サンプルコード

#include <iostream>
using namespace std;
enum direction {East, West, North, South};
int main() {
   direction dir;
   dir = South;
   cout<<dir;
   return 0;
}

出力結果

3

C++でenumを使う理由

enumの概要と基本的な使い方がわかったところで、なぜenumを使うのかについて見ていきましょう。

enumは、変数が取り得る値が限定されている場合にこそ活躍します。例えば、方角を格納するdir変数を考えてみてください。方角は4つしかないため、この変数は4つの値のどれか1つだけを持つべきです。誤って無関係な値を代入しようとするとコンパイルエラーが発生するため、コンパイル時のチェックが強化され、不正な定数を渡してしまうことで起こるバグを未然に防げます。

また、enumが頻繁に使われるもう一つの重要な場面がswitch文です。caseブロックが想定するすべての値をenumで定義しておけば、switchの括弧内に渡すenum変数が、本来受け付けるべきでない任意の値を持たないことを保証できます。


まとめ:3つの定義方法の使い分け

  • static const:型情報を持つため型安全性が高く、スコープやリンケージも制御できます。デバッガ上でも値を確認できるため、モダンなC++では最も推奨される方法です。

  • #define:プリプロセッサによる単純なテキスト置換です。型の概念がなくスコープも持たないため、名前の衝突や予期しない置換に注意が必要です。

  • enum:関連性のある複数の整数定数をひとつのグループとしてまとめられます。取り得る値を限定できるため、可読性と安全性の両面で優れています。

  1. JavaScriptのconst宣言とは?再代入できない変数の基本と使い方を解説

    JavaScriptのconst宣言は、値を再代入することも後から再宣言することもできない変数を作成するための構文です。constはES2015(ES6)で導入されました。 const宣言の主な特徴 一度値を代入すると、別の値に再代入することはできません。 同じ名前の変数を同じスコープ内で再宣言するとエラーになります。 宣言時に必ず初期値を代入する必要があります。 ブロックスコープ({}内でのみ有効)を持ちます。 それでは、JavaScriptにおけるconst宣言の実際のコードを見ていきましょう。 サンプルコード <!DOCTYPE html> <html>

  2. 【Swift入門】静的変数(static変数)とは?定義方法と使い方を実例で解説

    Swiftにおける静的変数(static変数)とは?静的変数の具体的な使い方を確認する前に、まずは「Swiftにおける静的変数とは何か」という基本概念を理解しておきましょう。静的変数の基本概念静的変数とは、クラスのすべてのインスタンス(オブジェクト)間で値が共有される変数のことです。変数をstaticとして宣言すると、その変数は個々のオブジェクトではなく、クラスそのものに紐づけられます。また、静的変数のためのメモリは、クラスがロードされるタイミングで一度だけ確保されます。図でイメージすると分かりやすいでしょう。Sampleクラスから生成された2つのオブジェクトs1とs2があるとします。s1とs