なぜ「できるだけconst,enum,inline」で#defineを置き換えるのか

8010 ワード

#define ASPECT_RATIO 1.653

Probelms: ASPECT_RATIOは、符号テーブル(symbol table)に戻ることなく、コンパイル前にプリプロセッサによって持ち去られ、コンパイルエラー時に符号に従ってソースを追跡することができなくなる.プリプロセッサが「マクロ名ASPECT_RATIOを盲目的に1.653に置き換える」ことにより、ターゲットコード(object code)に差分1.653が生じる可能性がある.
//            (#define)
const doubel AspectRatio = 1.653;//         ,        

**#define**を定数で置き換える2つの特殊な状況:1.定数ポインタの定義
異なるソースコードに含まれるのを容易にするために、定数定義式は通常ヘッダファイルに格納されるため、定数ポインタをconstとして宣言する必要がある.
//            char*   
const char* const AspectName = "Suger Master";
//  string    char*
const std::string AspectName = ("Suger Master");

2.class専属定数
定数の役割ドメイン(scope)をclass内に制限するには、定数をclassのメンバー(member)にする必要があります.この定数が最大1つのエンティティしかないことを確認するには、staticメンバーにする必要があります.
class ScoPlayer {
      
private:
	static const int NumTurns = 5;	//     
	int scores[NumTurns];					//     
}

説明:なぜ定義式ではなく宣言式なのか.(通常C++はあなたが使用しているものに対して定義式を提供することを要求します)答え:class専属定数に属してstaticで整形(integral type)である場合、特別な処理が必要です.アドレスを取らない場合、定義式を提供する必要がなく、宣言して使用することができます.class専属定数のアドレスが必要な場合、またはアドレスを取らずにコンパイラは定義式~~何の鬼?~~を見ることを堅持する場合は、次の定義式を提供する必要があります.
const int ScoPlayer::NumTurns;	//NumTurns   ;
//  :       ?
//  :                  。  class           (             5),         

注意:defineは役割ドメイン(scope)を重視していないため、マクロが定義されると、その後のコンパイル中に有効になります.(どこかで#undefによってよくわからない限り).したがって、これは、#defineがclass固有定数を定義するために使用されるだけでなく、いわゆるprivate#defineのようなものがないというパッケージ性を提供することもできないことを意味する.constメンバー変数はパッケージ化することができる.
//              
class CostEstimate{
      
private:
		static const double FudgeFactor;	//static class     ,      
}const double
		CostEstimate::FudgeFactor =1.35;	//static class     ,       

万一、コンパイラが「static整数型class定数」が「in class」の「初期値設定」を完了することを許さない場合は、いわゆる「the enum hack」補償方法に変更します.
「the enum hack補償方法」
その理論的基礎は、intsが使用されるときに列挙タイプ(enumerated type)に属する数値が重み付けされ、ScoPlayerは以下のように定義することができる.
class Scoplayer{
      
private:
		enum{
       NumTurns = 5};		//"the enum hack"—— NumTurns  5       。
		int scores[NumTurns];			//     

Enum hackはconstではなくdefineに似ています.たとえば、constはアドレスを取ることができますが、enumアドレスを1つ取るのは合法ではありません.defineのアドレスを1つ取るのは通常合法ではありません.
類似関数のマクロ(macros)については、define.をinline関数に置き換えることが望ましい.
// a b      f
#define CALL_WITH_MAX(a,b)	f((a) >(b) ? (a) :(b))
int a = 5,b=0;
CALL_WITH_MAX(++a, b);		//a      
//  :   a     ;   true,  a     ,   7
CALL_WITH_MAX(++a,b+10);		//a     
//  :   false,     

マクロがもたらす効率と一般関数のすべての予想可能な挙動とタイプセキュリティ(type safety)を得るためにtemplate inline関数を用いることができる.
template<typename T>
inline void callWithMax(const T& a, const T& b)
{
     
	f(a > b ? a : b);
}
//  “class  private inline   ”

まとめ:consts、enum、inlineにより、プリプロセッサ(特に#define)のニーズを低減できますが、完全に解消されるわけではありません.現在も#ifdef/#ifndefが制御コンパイルを継続する重要な役割を果たす必要があります.