例外は、プログラムの実行中に発生する問題です。C ++例外は、ゼロ除算の試行など、プログラムの実行中に発生する特別な条件です。
関数の例外宣言のリスト
プログラムの可読性と保守性を向上させ、プログラマーが関数の使用時に関数がスローする可能性のある例外を確認できるようにするために、C ++では、関数が宣言および定義されたときにスローできる例外を追加できます。例外のリストは次のように記述されます。次のとおりです。
void func() throw (int, double, A, B, C);
または
void func() throw (int, double, A, B, C){...}
上記の記述は、funcがint、double、A、B、およびCの3種類の例外をスローする可能性があることを示しています。例外宣言リストは、関数が宣言されたとき、または関数が定義されたときに書き込むことができます。両方の場所に書く場合、2つの場所は同じである必要があります。
例外宣言リストが次のように記述されている場合:
void func() throw ();
これは、func関数が例外をスローしないことを意味します。
関数がスローできる例外のタイプを説明していない場合、関数は任意のタイプの例外をスローできます。
関数が例外宣言リストにない例外をスローした場合、コンパイル時にエラーは発生しませんが、実行時に、Dev C ++によってコンパイルされたプログラムにエラーが発生します。VisualStudio2010でコンパイルされたプログラムは発生しません。エラー。宣言リストは実際的な効果はありません。
例外は、プログラムの制御を移す方法を提供します。C ++の例外処理には、try、catch、throwの3つのキーワードが含まれます。
- throw: 問題が発生すると、プログラムは例外をスローします。これは、throw キーワードを使用して実行され ます。
- catch: 問題を処理する場所で、例外ハンドラーを介して例外をキャッチします。catch キーワードは、例外をキャッチするために使用されます。
- try: try ブロックのコードは、アクティブ化される特定の例外を識別します。通常、その後に1つ以上のキャッチブロックが続きます。
ブロックが例外をスローした場合、例外をキャッチする方法では、 try キーワード と catchキーワードを使用します。例外をスローする可能性のあるコードをtryブロックに配置します。tryブロック内のコードは保護コードと呼ばれます。try / catchステートメントを使用するための構文は次のとおりです。
try
{
// 保护代码
}catch( ExceptionName e1 )
{
// catch 块
}catch( ExceptionName e2 )
{
// catch 块
}catch( ExceptionName eN )
{
// catch 块
}
try ブロックがさまざまな状況でさまざまな例外をスローする場合は、 複数のcatch ステートメントをリストして、さまざまなタイプの例外をキャッチすることができ ます。
C ++例外処理の基本構文
C ++は、throwステートメントとtry ... catchステートメントを介して例外処理を実装します。throwステートメントの構文は次のとおりです。
throw 表达式;
このステートメントは例外をスローします。例外は、値型が基本型またはクラスである式です。
try ... catchステートメントの構文は次のとおりです。
try {
语句组
}
catch(异常类型) {
异常处理代码
}
...
catch(异常类型) {
异常处理代码
}
複数のキャッチが存在する可能性がありますが、少なくとも1つです。
次の{}のtryとコンテンツを「tryブロック」と呼び、次の{}のcatchとコンテンツを「catchブロック」と呼びたい場合があります。
例外をスローする
throw ステートメントを使用して、コードブロック内の任意の場所に例外をスローできます 。throwステートメントのオペランドは任意の式にすることができ、式の結果のタイプによって、スローされる例外のタイプが決まります。
以下は、ゼロ除算を試みたときにスローされる例外の例です。
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
キャッチ例外
catch ブロックはtry ブロックの後に続き、 例外をキャッチします。キャッチする例外のタイプを指定できます。これは、catchキーワードの後の括弧内の例外宣言によって決定されます。
try ... catchステートメントの実行プロセスは次のとおりです。
- tryブロック内のステートメントを実行します。実行中に例外がスローされない場合、最後のcatchブロックの後のステートメントは実行後に実行され、catchブロック内のすべてのステートメントは実行されません。
- tryブロックの実行中に例外がスローされた場合は、例外がスローされた後、すぐに最初の「例外タイプ」とcatchブロックのスローされた例外タイプにジャンプします(例外は「catchブロックによってキャッチ」と呼ばれます」 )、実行後、最後のcatchブロックにジャンプして実行を続行します。
try
{
// 保护代码
}catch( ExceptionName e )
{
// 处理 ExceptionName 异常的代码
}
上記のコードは 、タイプExceptionNameの例外をキャッチし ます。以下に示すように、catchブロックでtryブロックによってスローされたあらゆるタイプの例外を処理する場合は、例外宣言の括弧内に省略記号...を使用する必要があります。
try
{
// 保护代码
}catch(...)
{
// 能处理任何异常的代码
}
以下は例です。ゼロで除算された例外をスローし、catchブロックで例外をキャッチします。
#include <iostream>
using namespace std;
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
int main ()
{
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
}catch (const char* msg) {
cerr << msg << endl;
}
return 0;
}
const char *型の 例外をスローするため、 例外をキャッチするときは、catchブロックでconst char *を使用する必要があります。上記のコードをコンパイルして実行すると、次の結果が生成されます。
Division by zero condition!
スローされた例外がcatchブロックによってキャッチされない場合、たとえば、catch(int e)をcatch(char e)に変更します。入力nが0の場合、スローされた整数例外はcatchブロックによってキャッチされません。例外は処理されないため、プログラムはすぐに終了し、try ... catchの後のコンテンツは実行されません。
C ++標準例外
C ++は、その中で定義されている一連の標準例外を提供します。これらの標準例外をプログラムで使用できます。これらは、以下に示すように、親クラスと子クラスの階層で編成されています。
次の表は、上記の階層の各例外の説明です。
上記の例外クラスを以下に紹介します。このセクションのプログラムの出力は、Visual Studio2010に基づいています。DevC++によってコンパイルされたプログラムの出力は異なります。
1)bad_typeid
typeid演算子を使用する場合、そのオペランドがポリモーフィッククラスへのポインターであり、ポインターの値がNULLの場合、この例外がスローされます。
2)bad_cast
dynamic_castを使用してポリモーフィック基本クラスオブジェクト(または参照)から派生クラスの参照にキャストする場合、変換が安全でない場合、この例外がスローされます。プログラム例は次のとおりです。
#include <iostream>
#include <stdexcept>
using namespace std;
int main()
{
try {
char * p = new char[0x7fffffff]; //无法分配这么多空间,会抛出异常
}
catch (bad_alloc & e) {
cerr << e.what() << endl;
}
return 0;
}
プログラムの出力は次のとおりです。
Bad dynamic_cast!
PrintObj関数で、bがdynamic_castを介してDerivedオブジェクトを参照しているかどうかを確認します。参照している場合は、そのPrintメンバー関数を呼び出します。そうでない場合は、例外をスローし、Derived :: Printを呼び出さないでください。
3)bad_alloc
new演算子を使用した動的メモリ割り当て中に、十分なメモリがない場合、この例外がスローされます。プログラム例は次のとおりです。
#include <iostream>
#include <stdexcept>
using namespace std;
int main()
{
try {
char * p = new char[0x7fffffff]; //无法分配这么多空间,会抛出异常
}
catch (bad_alloc & e) {
cerr << e.what() << endl;
}
return 0;
}
プログラムの出力は次のとおりです。
bad allocation
ios_base::failure
デフォルトの状態では、入力ストリームオブジェクトと出力ストリームオブジェクトはこの例外をスローしません。ストリームオブジェクトの例外メンバー関数でいくつかのフラグビットが設定されている場合、ファイルを開くときにエラーが発生したとき、または入力ストリーム内のファイルの終わりが読み取られたときに、この例外がスローされます。ここでは繰り返しません。
4)out_of_range
ベクトルまたは文字列のatメンバー関数を使用して添え字に基づいて要素にアクセスする場合、添え字が範囲外の場合、この例外がスローされます。例えば:
#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<int> v(10);
try {
v.at(100) = 100; //拋出 out_of_range 异常
}
catch (out_of_range & e) {
cerr << e.what() << endl;
}
string s = "hello";
try {
char c = s.at(100); //拋出 out_of_range 异常
}
catch (out_of_range & e) {
cerr << e.what() << endl;
}
return 0;
}
プログラムの出力は次のとおりです。
invalid vector <T> subscript
invalid string position
v.at(100)をv [100]に置き換え、s.at(100)をs [100]に置き換えると、プログラムは例外を発生させません(ただし、プログラムがクラッシュする可能性があります)。atメンバー関数は、範囲外の添え字を検出して例外をスローしますが、operator []は検出しないためです。atに対する演算子[]の利点は、添え字が範囲外かどうかを判断する必要がないため、実行速度が速くなることです。
新しい例外を定義する
例外 クラスを継承してオーバーロードすることにより、新しい例外を定義でき ます。次の例は、std :: exceptionクラスを使用して独自の例外を実装する方法を示しています。
#include <iostream>
#include <exception>
using namespace std;
struct MyException : public exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
};
int main()
{
try
{
throw MyException();
}
catch(MyException& e)
{
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
}
catch(std::exception& e)
{
//其他的错误
}
}
これにより、次の結果が生成されます。
MyException caught
C++ Exception
ここで、what() は、すべてのサブ例外クラスによってオーバーロードされた例外クラスによって提供されるパブリックメソッドです。これにより、例外の理由が返されます。
C / C ++を学びたいと思っている友達、考えがなく、学び始める方法がわからない場合は、グループに参加してください:1151395975、私に従って学習してください。また、無料の学習資料をたくさん受け取ることができます。