C++タイプの安全について


タイプセキュリティとは?
タイプセキュリティはメモリセキュリティに大きく等価であり、タイプセキュリティのコードは自分が許可されていないメモリ領域にアクセスしようとしません.「タイプセキュリティ」は、プログラミング言語を形容するためによく用いられ、そのプログラミング言語がタイプセキュリティを保障するメカニズムを提供するかどうかに基づいている.あるプログラムを「タイプセキュリティ」で形容する場合もあり、判別の基準はそのプログラムにタイプエラーが隠されているかどうかにある.タイプセキュリティのプログラミング言語とタイプセキュリティのプログラムの間には、必然的なつながりはありません.良いプログラマーはタイプがそんなに安全ではない言語を使ってタイプがかなり安全なプログラムを書くことができますが、逆に、もう少しのプログラマーはタイプがかなり安全な言語を使ってタイプがあまり安全ではないプログラムを書くことができます.絶対型の安全なプログラミング言語はまだありません.
C言語のタイプセキュリティ
Cは、ある構造体のポインタから別の構造体のポインタに変換しようとすると、コンパイラがエラーを報告します.明示的なタイプ変換を使用しない限り.しかしながら、Cにおけるかなりの操作は安全ではない.次の2つの非常に一般的な例を示します.
(1)printf形式出力
/* - print.cpp
 * version:1.1
 */
int main()
{
	printf("%d
",10); system("pause"); return 0; }

上のコードは簡単です.printf関数では、%dは10と一致し、結果は正しいです.
少し変更:
/* - print.cpp
 * version:1.2
 */
int main()
{
	printf("%f
",10); system("pause"); return 0; }

%f浮動小数点数は10と一致しないが、コンパイルが通過し、実行も間違っていないが、結果は:
0.000000任意のキーを押して続行してください.さらに,%fを%sに変更し,コンパイルを通過し,Access Violationをエラーとして実行する.
(2)malloc関数の戻り値
mallocはCでメモリ割り当てを行う関数で、その戻りタイプはvoid*すなわち空のタイプポインタであり、char*pStr=(char*)malloc(100*sizeof(char))という使い方がしばしばあり、ここでは明らかに明示的なタイプ変換が行われている.タイプマッチングはまだ問題ありませんが、int*pInt=(int*)malloc(100*sizeof(char))が発生すると、いくつかの問題が発生する可能性がありますが、このような変換Cはエラーを提示しません.
C++のタイプセキュリティ
C++が適切に使用されている場合、Cよりはるかにタイプのセキュリティがあります.Cに比べて、C++はいくつかの新しいメカニズム保障タイプの安全を提供しています.
(1)オペレータnewが返すポインタタイプはvoid*ではなくオブジェクトと厳密に一致する.
(2)Cの多くのvoid*をパラメータとする関数はC++テンプレート関数に書き換えることができ、テンプレートはタイプチェックをサポートする.
(3)define constantsの代わりにconstキーワードを導入する.これはタイプがあり、役割ドメインがあるが、define constantsは簡単なテキスト置換にすぎない.
(4)一部のdefineマクロはinline関数に書き換えることができ、関数のリロードと結びつけて、タイプの安全を前提に多種のタイプをサポートすることができ、もちろんテンプレートに書き換えることもタイプの安全を保証することができる.
(5)C++はdynamic_を提供するcastキーワードはdynamic_のため、変換プロセスをより安全にします.cast比static_castは、より具体的なタイプのチェックに関連しています.
それでも、C++は絶対的なタイプの安全なプログラミング言語ではありません.使用が適切でない場合、タイプの安全は保証されません.たとえば、次の2つの例があります.
	int i=5;
	void* pInt=&i;
	double d=(*(double*)pInt);
	cout<<d<<endl;

入力結果は5ではなく、予想外の結果:-9.25596 e+061です.たとえば、
#include<iostream>
using namespace std;

class Parent
{
};
class Child1:public Parent
{
public:
	int i;
	Child1(int e):i(e)
	{
	}
};
class Child2:public Parent
{
public:
	double d;
	Child2(double e):d(e)
	{
	}
};
int main()
{
	Child1 c1(5);
	Child2 c2(4.1);
	Parent* pp;
	Child1* pc1;

	pp=&c1;
	pc1=(Child1*)pp;  //#1     ,       Child1*,     
	cout<<pc1->i<<endl;

	pp=&c2;
	pc1=(Child1*)pp;  //#2     ,       ,     
	cout<<pc1->i<<endl;
	system("pause");
	return 0;
}

結果は次のとおりです.
5 1717986918任意のキーを押して続行してください.
上記の2つの例がタイプの不安全な問題を引き起こしたのは,プログラマーの使用が適切ではないからである.1つ目の例は空のタイプポインタvoid*を使用し、2つ目の例は2つのタイプポインタ間で強制変換を行う.したがって、プログラムのタイプセキュリティを保証するには、空のタイプポインタvoid*の使用をできるだけ避け、2つのタイプポインタを強制的に変換しないようにしなければならない.