Sunday, October 8, 2017

Kuliah 9 C++: Penanganan Eksepsi


BAB 9.
Penanganan Eksepsi






9.1 Pengantar: Klausa try, throw, dan catch
Dalam C++, penanganan eksepsi dikelola dengan memanfaatkan tiga katakunci, yaitu try, throw, dan catch. Programer perlu mengidentifikasi di bagian program mana sebuah eksepsi paling mungkin bisa terjadi. Sebagai contoh, bagian program dimana program melakukan pembacaan masukan dari user adalah di mana tempat paling mungkin terjadinya error ketika user memasukkan data yang salah. Contoh yang lain adalah saat pembagian integer. Eksepsi bisa terjadi ketika penyebut bernilai nol. Statemen-statemen semacam itu perlu ditempatkan di dalam sebuah blok try. Blok try diawali dengan katakunci try yang diikuti dengan statemen-statemen yang ditempatkan di dalam kurung kurawal { dan }. Blok try, umumnya, memuat kondisi-kondisi seleksi untuk nilai-nilai variabel yang mungkin bisa menyebabkan terjadinya eksepsi. Ini disebut dengan mekanisme deteksi. Jika sebuah eksepsi dideteksi, maka eksepsi itu akan dilemparkan menggunakan katakunci throw seperti diilustrasikan pada kode berikut.

try                        //blok try
{
   statemen_statemen;     
   throw tipe_eksepsi;     //jika eksepsi dideteksi, eksepsi akan dilempar
}

catch (tipe_eksepsi1)      //blok catch pertama
{
   statemen_statemen;
}

catch(tipe_eksepsi2)              //blok catch kedua
{
   statemen_statemen;
}

Perhatikan bahwa segmen throw diikuti oleh satu atau lebih blok catch. Setiap blok catch diawali dengan katakunci catch yang diikuti dengan kurung () yang memuat tipe data blok catch, yang kemudian diikuti dengan statemen-statemen blok catch yang diapit di antara kurung kurawal { dan }. Setiap blok catch memiliki tipe yang berbeda untuk ditangkap. Di sini, tipe mengacu pada salah satu dari tipe-tipe fundamental seperti int, float, double, atau char, atau tipe-tipe yang didefinisikan oleh user seperti nama kelas dari objek yang dilempar. Pemilihan dari blok catch tertentu tergantung pada hasil dari kesesuaian tipe yang dilempar dengan tipe dari blok catch. Jadi, tipe blok catch tidak boleh sama. Proses ini diilustrasikan pada Gambar 9.1.


GAMBAR 9.1 Ilustrasi dari try, throw, dan catch


Program berikut mengilustrasikan eksepsi yang terjadi ketika pembagian nol dilakukan.

Program 9.1 Mengilustrasikan aplikasi dari try, throw, dan catch

#include<iostream>
using namespace std;

int main ()
{
   int A, B;
   double D;

   cout<<"Masukkan dua nilai: ";
   cin>> A>>B;

   try //blok try
   {
      if( B == 0)
      throw B;       //melempar eksepsi

      else
      {
         D = A/double(B);
         cout<<"D = "<<D<<endl;
      }
   } //akhir dari blok try

   catch (int C)     //blok penanganan eksepsi diawali di sini
   {
          cout<<"Anda memasukkan B = 0, masukkan nilai lain"<<endl;
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 4 0
Anda memasukkan B = 0, masukkan nilai lain


Perlu diketahui bahwa int C adalah variabel lokal dari blok catch. Proses penangkapan eksepsi bersifat sensitif terhadap tipe. Blok penangkapan eksepsi hanya akan menangkap tipe dari apa yang dilempar yang sesuai dengan tipe yang dideklarikan di dalam blok catch. Blok try bisa saja diikuti oleh sejumlah blok catch, masing-masing dengan tipe yang berbeda. Jika tipe dari apa yang dilempar dan tipe dari apa yang dideklarasikan pada blok catch berbeda, maka blok catch tersebut akan dilompati. Pada dasarnya, penamaan variabel, seperti C, pada program 9.1 adalah sesuatu yang tidak perlu. Anda cukup hanya menuliskan statemen tersebut sebagai catch(int). Itu adalah tipe dari variabel yang dilemparkan. Program berikut merupakan contoh lain yang mengilustrasikan ketika tipe objek yang dilempar adalah double. Jadi, blok catch dengan argumen double lah yang akan menanganinya.

Program 9.2 Mengilustrasikan bahwa tipe eksepsi yang dilempar harus sesuai dengan tipe dari blok catch

#include<iostream>
using namespace std;

int main ()
{
   int A ;
   double B, D ;

   cout<<"Masukkan dua nilai: ";
   cin>>A>>B;

   try //blok try
   {
      if(B == 0.0)
         throw B;    //melempar eksepsi bertipe double
      else
         {
         D = A/B;
         cout<<"D = "<<D<<endl;
         }
   } //akhir dari blok try

   catch(int)        //blok penanganan eksepsi untuk int
   {
      cout<<"Eksepsi tipe \"int\" ditangkap."<<endl;
   }

   catch(double)     //blok penanganan eksepsi untuk double
   {
      cout<<"Eksepsi tipe \"double\" ditangkap."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 5 0
Eksepsi tipe "double" ditangkap.


Program 9.3 Mengilustrasikan bahwa ketika tidak ada tipe dari blok catch yang cocok dengan tipe yang dilempar, program akan berhenti secara tidak normal

#include<iostream>
using namespace std;

int main ()
{
   int A;
   double B, D;
   char ch = 'C';

   cout<<"Masukkan dua nilai: ";
   cin>>A>>B;

   try //blok try
   {
      if(B == 0.0)
         throw ch; //melempar tipe char
      else
         {
         D = A/B;
         cout<<"D = "<<D<<endl;
         }
   } //akhir dari blok try

   catch (int)             //blok penanganan eksepsi untuk int
   {
      cout<<"Eksepsi tipe \"int\" ditangkap."<<endl;
   }

   catch(double)     //blok penanganan eksepsi untuk double
   {
      cout<<"Eksepsi tipe \"double\" ditangkap."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 5 0
abnormal program termination.


Pada program tersebut, tipe dari eksepsi yang dilempar adalah char, sedangkan tipe dari apa yang ditangkap adalah int dan double. Jadi, tidak satupun dari kedua tipe dari blok catch cocok dengan tipe eksepsi. Pada kasus semacam itu, fungsi abort() akan dipanggil untuk menutup program. Program juga menunjukkan bahwa tipe eksepsi yang dilempar tidak harus sama dengan tipe variabel yang terlibat di dalam eksepsi. Program berikut menunjukkan bahwa eksepsi yang dilempar adalah sebuah objek kelas. Pada kasus itu, nama kelas adalah tipe eksepsi yang dilempar. Ketika sebuah objek kelas dilempar, maka tipe eksepsi adalah nama dari kelas itu.

Program 9.4 Mengilustrasikan bahwa eksepsi yang dilempar adalah sebuah objek kelas

#include<iostream>
using namespace std;

class Basis          //kelas Basis didefinisikan
{ };

int main()
{
   Basis obj_basis ; //obj_basis adalah objek dari kelas Basis

   int A;
   double B, D;
   char ch = 'C';

   cout<<"Masukkan dua nilai: ";
   cin>> A>>B;

   try //blok try
   {
      if(B == 0.0)
         throw obj_basis; //melempar sebuah objek dari kelas Basis
      else
      {
         D = A/B ;
         cout<<"D = "<<D<<endl;
      }
   } //akhir dari blok try

   catch (int) //blok penanganan eksepsi untuk int
   {
      cout<<"Eksepsi tipe \"int\" ditangkap."<<endl;
   }

   catch(Basis) //blok penanganan eksepsi untuk kelas Basis
   {
      cout<<"Eksepsi tipe \"Basis\" ditangkap."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 5 0
Eksepsi tipe "Basis" ditangkap.


Pada program berikut, sebuah kelas dengan Kecuali didefinisikan. Statamen throw dipakai untuk melemparkan sebuah objek Kec dari kelas Kecuali. Pada blok catch, tipe sama, yaitu Kecuali, tetapi objek sekarang adalah Kecd. Eksepsi ditangkap karena tipe sama. Jika lebih dari satu eksepsi yang bertipe sama dilemparkan, maka hanya satu blok catch yang diperlukan untuk menangkapnya. Untuk membedakan dua eksepsi, statemen seleksi perlu disediakan di dalam blok catch sehingga penanganan eksepsi dapat dilakukan sesuai dengan yang diinginkan.

Program 9.5 Mengilustrasikan bahwa beberapa eksepsi dapat dilemparkan dari blok try yang sama

#include<iostream>
using namespace std;

class Kecuali{
   public:
      void Tampil1( )
      {
         cout<<"Terjadi sebuah eksepsi.\nNilai yang dimasukkan untuk A adalah negatif\n";
         cout <<"Msukkan nilai positif.\n";
      }

      void Tampil2 ()
      {
         cout<<"Nilai B yang dimasukkan adalah nol. \n";
         cout<<"Masukkan sebuah nilai lebih besar dari nol.\n";
      }
};

int main ()
{
   Kecuali Kec;
   int A, B ;
   double D;

   cout<<"Masukkan dua nilai: ";
   cin>> A>>B;

   try
   {
      if (B == 0)
         throw Kec ;
      else
         if (A < 0)
            throw Kec;
         else
         {
            D = A/ double(B);
            cout<<"D = "<<D<<end
         }
   }

   catch (Kecuali Kecd)
   {
      if (A < 0)
         Kecd.Tampil1();
      if (B == 0)
         Kecd.Tampil2();
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 4 0
Nilai B yang dimasukkan adalah nol.
Masukkan sebuah nilai lebih besar dari nol.


Blok try dapat memiliki lebih dari satu statemen throw. Selain itu, blok try juga dapat diikuti oleh lebih dari satu blok catch tetapi argumen-argumennya harus berbeda tipe. Satu blok catch tidak bisa memiliki dua tipe berbeda sebagai argumennya. Misalnya, catch(int A, double B) akan menghasilkan error kompilasi. Pada program berikut, dua tipe yang berbeda dilemparkan dari blok try yang sama, dan ia memerlukan dua blok catch yang berbeda, satu untuk tiap tipe.

Program 9.6 Mengilustrasikan bahwa beberapa eksepsi dapat dilemparkan dari blok try yang sama, yang memerlukan dua blok catch yang berbeda

#include<iostream>
using namespace std;

int main ()
{
   int A;
   double D, B;

   cout<<"Masukkan dua nilai: ";
   cin>>A>>B;

   try
   {
      if (B == 0)
         throw B;
      if (A > 50)
         throw A;
      else
      {
         D = A/ B;
         cout<<"D = "<<D<<endl;
      }
   }

   catch (double C)
   {
      cout<<"Anda masukkan B = 0, silahkan masukkan nilai lain."<<endl;
   }

   catch (int E )
   {
      cout<<"Silahkan masukkan nilai lain yang kurang dari 50 untuk A."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 75 5
Silahkan masukkan nilai lain yang kurang dari 50 untuk A.

Di dalam blok try yang sama, Anda bisa memiliki beberapa statemen throw. Jika semua eksepsi yang dilemparkan bertipe sama, maa hanya diperlukan satu blok catch untuk menangkapnya. Untuk informasi bagi user tentang eksepsi mana yang ditangkap, sejumlah statemen seleksi perlu dicantumkan di dalam blok catch tersebut. Seperti yang terjadi pada statemen-statemen seleksi, jika satu statemen diseleksi, maka statemen-statemen lain akan diabaikan.



9.2 Menangkap Semua Tipe Eksepsi
Untuk menangkap semua tipe eksepsi yang dilemparkan, kode catch(…) dapat digunakan. Perhatikan bahwa hanya ada tiga titik di dalam kurung tersebut. Program berikut mengilustrasikan catch(…).

Program 9.7 Mengilustrasikan penggunaan catch(…) untuk menangkap semua eksepsi

#include<iostream>
using namespace std;

class Basis
{ };

int main ()
{
   Basis obj_basis ;

   int A;
   double B, D;
   char ch;

   cout<<"Masukkan sebuah integer, sebuah double, dan sebuah karakter: ";
   cin>>A>>B>>ch;

   try
   {
      if(B == 0.0)
         throw obj_basis;
      if (A > 50)
         throw A;
      if(ch != 'Z')
         throw ch;
      else
      {
         D = A/double(B);
         cout <<"D = "<<D<<endl;
      }
   } //akhir dari blok try

   catch (...) //blok penanganan eksepsi diawali di sini
   {
      if (A >50)
         cout<<"Eksepsi pada int ditangkap."<<endl;
      if (B==0)
         cout<<"Eksepsi pada Basis ditangkap."<<endl;
      if(ch != 'Z')
         cout<<"Eksepsi pada char ditangkap."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan sebuah integer, sebuah double, dan sebuah karakter: 30 6.5 Z
D = 4.61538

Masukkan sebuah integer, sebuah double, dan sebuah karakter: 56 0 H
Eksepsi pada int ditangkap.
Eksepsi pada Basis ditangkap.
Eksepsi pada char ditangkap.



9.3 Fungsi untuk Menangani Eksepsi
Runtun try-throw dan catch bisa ditempatkan ke dalam suatu fungsi. Adalah lebih mudah untuk memanggil fungsi di dalam program utama. Program berikut mengilustrasikannya.

Program 9.8 Mengilustrasikan aplikasi dari fungsi penanganan eksepsi

#include<iostream>
using namespace std;

void Uji(int A, double B, char ch)
{
   try
   {
      if (A > 50.0)
      {
         cout <<"A berada di luar rentang"<<endl;
         throw A;
      }
      if (B == 0)
      {
         cout <<"B sama dengan nol"<<endl;
         throw B;
      }
      if (ch != 'D')
      {
         cout<<"ch tidak sama dengan D"<<endl;
         throw ch;
      }
      else
         cout<<"Semua berada di dalam rentang. Tidak ada eksepsi yang dilempar." <<endl;
   }

   catch (...)
   {
      cout<<"Menangkap sebuah eksepsi"<<endl;
   }
}

int main ()
{
   int A;
   double B;
   char ch;

   cout<<"Tulislah nilai A, b, dan ch: ";
   cin>>A>>B>>ch;

   Uji(A,B,ch);            //fungsi uji untuk try, throw dan catch

   return 0;
}
KELUARAN
Tulislah nilai A, b, dan ch: 50 4.6 F
ch tidak sama dengan D
Menangkap sebuah eksepsi

Tulislah nilai A, b, dan ch: 65.5 40.5 F
A berada di luar rentang
Menangkap sebuah eksepsi



9.4 Spesifikasi Eksepsi
C++ dapat dipakai oleh user untuk mendeklarasikan sejumlah eksepsi yang dapat dilempar oleh sebuah fungsi. Spesifikasi eksepsi pada dasarnya imbuhan pada kepala fungsi yang biasa (normal). Imbuhan tersebut terdiri-dari katakunci throw, yang diikuti, di dalam kurung, daftar tipe eksepsi. Definisi fungsi dengan sebuah spesifikasi eksepsi memiliki format berikut:

tipe pengenal_fungsi (daftar_argumen) throw (daftar_tipe_eksepsi) //kepala fungsi
{statemen_statemen;} //tubuh fungsi

Pada definisi di atas, kata pertama, tipe, adalah tipe data dari nilai balik yang dihasilkan fungsi. Kata tersebut diikuti oleh nama fungsi yang kemudian diikuti oleh daftar argumen di dalam kurung dan kemudian imbuhan yang memuat katakunci throw yang diikuti oleh daftar tipe eksepsi di dalam kurung. Tipe fungsi tidak dipengaruhi oleh imbuhan. Daftar tipe eksepsi dan daftar argumen bersifat opsional (boleh tidak ada). Jadi, perhatikan tiga kasus berikut:

a.        void Fungsi1() throw ()     //daftar_tipe_eksepsi kosong, tidak bisa melempar eksepsi.
b.       void Fungsi2() throw(X, Y, Z) //hanya dapat melempar tipe eksepsi X, Y, dan Z.
c.        void Fungsi3()              //dapat melempar sembarang tipe eksepsi

Jika fungsi melemparkan sebuah eksepsi yang tidak ada di dalam daftar_tipe_eksepsi, maka fungsi unexpected() akan dipanggil. Aksi default dari fungsi unexpected() adalah untuk memanggil fungsi abort() yang menghentikan program.


Fungsi dengan imbuhan throw() tidak dapat melemparkan eksepsi apapun dan jika ia melakukannya, maka fungsi unexpected() akan dipanggil dan program akan dihentikan. Sama halnya, jika fungsi dengan daftar_tipe_eksepsi, (X, Y, Z), melemparkan sebuah eksepsi selain X, Y, atau Z, maka program akan dihentikan. Opsi ketiga, void Fungsi3(), dapat melemparkan sembarang tipe eksepsi.

Program 9.9 Mengilustrasikan spesifikasi eksepsi

#include<iostream>
using namespace std;

void FEksepsi (int j) throw () //tidak dapat melemparkan eksepsi apapun
{
   if (j== 1)
      throw j;
   if (j == 2)
      throw char();
   if (j==3)
      throw double();
}

int main ()
{
   int n;

   cout<<"Masukkan sebuah nilai antara 1 sampai 3:";
   cin>>n ;

   try{
      FEksepsi(n);
   } //akhir blok try

   catch(int) //blok penanganan eksepsi diawali di sini
   {
      cout<<"Statemen throw int ditangkap"<<endl;
   }

   catch(double)
   {
      cout<<"Statemen throw double ditangkap"<<endl;}

   return 0;
}
KELUARAN
Masukkan sebuah nilai antara 1 sampai 3:2
abnormal program termination


Program 9.10 Mengilustrasikan bahwa jika tipe eksepsi yang dilemparkan tidak ada di dalam spesifikasi eksepsi, maka program akan dihentikan

#include<iostream>
using namespace std;

//fungsi berikut dapat melempar int atau double
void FEksepsi(int j) throw(int, double)
{
   if (j== 1)
      throw j;
   if (j == 2)
      throw 'D';
   if(j==3)
      throw 0.8;
}

int main ()
{
   int n;
  
   cout<<"Masukkan sebuah nilai antara 1 sampai 3: ";
   cin>>n ;

   try{
      FEksepsi(n);
   } //akhir blok try

   catch(int) //blok penanganan eksepsi diawali di sini
   {
      cout<<"Statemen throw int ditangkap"<<endl;
   }

   catch(double)
   {
      cout<<"Statemen throw double ditangkap"<<endl;}

   return 0;

}
KELUARAN
Masukkan sebuah nilai antara 1 sampai 3: 2
abnormal program termination


Program dijalankan dan nilai 2 dimasukkan. Ini berkaitan dengan pelemparan eksepsi bertipe char yang tidak ada di dalam daftar spesifikasi. Oleh karena itu, program dihentikan.

Pada program berikut, eksepsi yang dilemperkan berada di dalam daftar spesifikasi eksepsi.

Program 9.11 Mengilustrasikan implementasi dari eksepsi-eksepsi terdaftar

#include<iostream>
using namespace std;

void FungsiSpesifikasi(int j) throw (int, double, char)
{
   if (j == 1)
      throw j;
   if (j ==2)
      throw 0.6;
   if (j == 3)
      throw 'H';
}

int main ()
{
   try
   {
      int A (4);

         if (A != 3)
         FungsiSpesifikasi(1);
   }

   catch (int) //blok penanganan eksepsi diawali di sini
   {
      cout<<"Ekspesi pada int ditangkap"<<endl;
   }

   try { //blok try
      double B (6.6);

      if (B!=7)
         FungsiSpesifikasi(2);
   }

   catch (double) //blok penanganan eksepsi diawali di sini
   {
      cout<<"Ekspesi pada double ditangkap"<<endl;
   }

   try {
      char ch = 'C';

      if (ch != 'H')
         FungsiSpesifikasi(3);
   }

   catch(char)
   {
      cout<<"Ekspesi pada char ditangkap"<<endl;
   }

   return 0;
}
KELUARAN
Ekspesi pada int ditangkap
Ekspesi pada double ditangkap
Ekspesi pada char ditangkap



9.5 Melempar-Ulang Eksepsi
Sebuah eksepsi dapat ditangkap oleh suatu blok penanganan eksepsi dan hanya secara parsial ditangani. Programer bisa melemparkan ulang eksepsi tersebut sehingga dapat ditangani oleh mekanisme catch sebelah luar. Untuk kasus semacam itu, kode berikut perlu dicantumkan di dalam blok catch:

throw;

Kode ini akan melempar ulang tipe eksepsi yang sama sehingga ia dapat ditangani oleh blok catch sebelah luar. Eksepsi yang dilempar-ulang tidak ditangkap oleh blok catch yang sama. Eksepsi itu ditangkap oleh blok catch sebelah luar.

Program berikut mengilustrasikan pelemparan-ulang eksepsi.

Program 9.12 Mengilustrasikan implementasi dari eksepsi-eksepsi terdaftar

#include<iostream>
using namespace std;

void LemparUlang(int A) //definisi dari fungsi LemparUlang()
{
   try
   {
      int B;

      cout<<"Masukkan sebuah nilai positif: ";
      cin>> B ;

      if (B<=0)
         throw B;
   }

   catch (int)
   {
      cout<<"Blok catch ini di dalam fungsi LemparUlang."<<endl;
      throw; //LemparUlang kedua
   }
}

int main ()
{
   try{
      try {
         LemparUlang(6);
      }

      catch(int)
      {
         cout<<"Blok catch ini adalah blok catch dalam di dalam main."<<endl;
         throw; // LemparUlang kedua
      }
   }

   catch(int)
   {
      cout<<"Blok catch ini adalah blok catch luar di dalam main."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan sebuah nilai positif: -5
Blok catch ini di dalam fungsi LemparUlang.
Blok catch ini adalah blok catch dalam di dalam main.
Blok catch ini adalah blok catch luar di dalam main.



9.6 Kelas-Kelas Eksepsi Pustaka Standar C++
Ada sejumlah besar kelas di dalam pustaka standar C++ yang bisa menangani eksepsi. Gambar 9.2 menunjukkan hierarki dari kelas-kelas yang menangani eksepsi di dalam C++. File header <exception> mendefinisikan eksepsi kelas basis. Sejumlah kelas diderivasi dari kelas basis. Kelas-kelas tersebut termasuk logic_error, runtime_error, bac_alloc, bad_cast, bad_typid, dan bad_exception. Ada tiga kelas yang diderivasi dari kelas logic_error, yaitu kelas out_of_range, length_error, dan invalid_argument. Kelas-kelas yang berkaitan dengan runtime error dan logic error didefinisikan di dalam file header <stdexcept>. Empat kelas, yaitu bad_alloc, bad_cast, bad_typeid, dan bad_exception adalah tipe eksepsi yang dilemparkan oleh operator-operator. Kelas exceptio juga mendefinisikan sebuah fungsi virtual what() yang didefinisikan-ulang oleh semua kelas terderivasi untuk menyampaikan pesan tertentu.

Sejumlah kelas yang berkaitan dengan eksepsi dan kelas-kelas terderivasi diilustrasikan pada Gambar 9.2. Tabel 9.1 mengelaborasi sejumlah kelas eksepsi tersebut.
  


GAMBAR 9.2 Kelas-kelas eksepsi di dalam pustaka standar C++


TABEL 9.1 Sejumlah kelas eksepsi di dalam pustaka standar C++
Kelas
Penjelasan
overflow_error
Eksepsi ini berkaitan dengan sebuah nilai yang nilainya terlalu besar untuk komputer.
underflow_error
Eksepsi ini berkaitan dengan sebuah nilai yang nilainya terlalu kecil untuk komputer.
bad_alloc
Eksepsi yang dilemparkan oleh operator new pada kasus pengalokasian memori yang gagal (memori tidak tersedia).
bad_cast
Eksepsi ini dilemparkan oleh dynamic_cast jika tidak berhasil.
bad_typeid
Eksepsi ini dilemparkan oleh operator typeid() jika tidak berhasil.
bad_exception
Jika sebuah eksepsi yang tidak terdaftar di dalam spesifikasi eksepsi terjadi, maka eksepsi bad_exception akan dilemparkan oleh fungsi unexpected().
invalid_argument
Sebagai contoh, sebuah nilai negatif untuk akar kuadrat adalah argumen yang tak valid.
length_error
Mengindikasikan bahwa sebuah panjang lebih besar dari yang ditetapkan untuk objek yang digunakan.
out_of_range
Mengindikasikan ketika sebuah nilai melebihi rentang nilai yang diijinkan.


Program berikut merupakan sebuah ilustrasi dari aplikasi atas kelas eksepsi standar.

Program 9.13 Mengilustrasikan aplikasi dari overflod_error

#include <iostream>
#include <stdexcept>
using namespace std;

double Resiprokal(double A) throw (overflow_error)
{
   cout<<"Tulislah sebuah nilai sangat kecil :";
   cin>> A;

   if(A < 0.000001)
      throw overflow_error("Resiprokal terlalu besar.");

   return 1/A ;
}

int main ()
{
   try
   {
      double B =0.0;

         cout<<"Resiprokal dari B = "<<Resiprokal(B)<<endl;
   }

   catch (exception & x)
   {
      cout<<"Eksepsi -> "<< x.what()<<endl;
   }

   return 0;
}
KELUARAN
Tulislah sebuah nilai sangat kecil :0.000000001
Eksepsi -> Resiprokal terlalu besar.

Tulislah sebuah nilai sangat kecil :0.0005
Resiprokal dari B = 2000


Program berikut mengilustrasikan pelemparan eksepsi invalid_argument.

Program 9.14 Mengilustrasikan aplikasi dari fungsi standar dari kelas <exception>

#include<iostream>
using namespace std;
#include<cmath>
#include<exception>

double AkarKuadrat(int n) throw (invalid_argument)
{
   if (n < 0)
      throw logic_error("invalid_argument untuk akar kuadrat");

   return sqrt(n);
}

int main()
{
   int m;

   cout<<"Masukkan sebuah nilai integer: ";
   cin>>m;

   try
   {
      cout<<"Akar kuadrat dari "<<m<<" adalah "<<AkarKuadrat(m)<<endl;
   }

   catch (exception& eksp)
   {
      cout<<eksp.what()<<endl;
   }

   return 0;
}
KELUARAN
Masukkan sebuah nilai integer: -5
invalid_argument untuk akar kuadrat




9.7 Fungsi set_terminate()
Ketika sebuah eksepsi dilemparkan dan tidak ada blok catch yang menangkapnya, maka aksi defaultnya adalah fungsi terminate() dipanggil, yang secara default memanggil fungsi abort() untuk menghentikan program. Namun, programer dapat memiliki opsi kedua dengan mendefinisikan fungsi terminate() dan dengan medaftarkannya di dalam program menggunakan fungsi set_terminate(). Lihat program berikut untuk ilustrasi.
                                       
Program 9.15 Mengilustrasikan aplikasi dari fungsi set_terminate()

#include<iostream>
#include<stdexcept>
using namespace std;

void berhenti()
{
   cout<<"Sebuah eksepsi telah terjadi."<<endl;
   cout<<"Program dihentikan."<<endl;
   exit(1);
}

int main ()
{
   set_terminate(berhenti);

   try
   {
      int A;

         cout<<"Masukkan sebuah nilai yang lebih kecil dari 60: ";
      cin >> A;

      if (A > 60)
         throw A;

      cout<<"Nilai yang dimasukkan adalah "<<A<<endl;
   }

   catch (double)
   {
      cout<<"Nilai berada di luar rentang."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan sebuah nilai yang lebih kecil dari 60: 76
Sebuah eksepsi telah terjadi.
Program dihentikan.



LATIHAN
1.       Apa itu eksepsi di dalam C++?
2.       Jelaskan try, throw, dan catch yang berkaitan dengan eksepsi.
3.       Apa yang Anda pahami tentang spesifikasi eksepsi?
4.       Berikan sebuah contoh dari blok try.
5.       Apa yang harus cocok antara statemen throw dan blok catch sehingga eksepsi dapat ditangani?
6.       Apa kegunaan dari fungsi set_terminate()?
7.       Eksepsi manakah yang dilemparkan oleh operator new?
8.       Tuliskan sebuah program kecil untuk mengilustrasikan bagaimana mekanisme try, throw, dan catch bekerja.
9.       Apakah kode untuk menangkap semua tipe eksepsi?
10.    Tulislah sebuah program untuk menunjukkan bahwa jika objek kelas terderivasi dilemparkan, maka blok catch dengan tipe kelas basis dapat menangkapnya.
Jawaban:

Program 9.16 Mengilustrasikan bahwa jika objek kelas terderivasi dilemparkan, maka blok catch dengan tipe kelas basis dapat menangkapnya

#include<iostream>
using namespace std;

class Basis          //kelas Basis didefinisikan
{ };

class Terderivasi : public Basis //kelas Terderivasi didefinisikan
{};

int main ()
{
   Basis obj_basis ;       //obj_basis adalah objek dari kelas Basis

   Terderivasi obj_derivasi;      // obj_derivasi adalah objek dari kelas Terderivasi

   int A;
   double B, D ;
   char ch = 'C';

   cout<<"Masukkan dua nilai: ";
   cin>> A>>B;

   try //blok try
   {
      if (B == 0.0)
         throw obj_derivasi;      //melempar sebuah objek dari kelas Terderivasi
      else
      {
         D = A/B ;
         cout<<"D = "<< D <<endl;
      }
   } //akhir blok try

   catch (int) //blok penanganan eksepsi untuk int
   {
      cout<<"Eksepsi tipe \"int\" ditangkap."<<endl;
   }

   catch(Basis) //blok penanganan eksepsi untuk kelas Basis
   {
      cout<<"Eksepsi tipe \"Basis\" ditangkap."<<endl;
   }

   return 0;
}
KELUARAN
Masukkan dua nilai: 6.0 0.0
Eksepsi tipe "Basis" ditangkap.







No comments: