Bab. 1 Kelas Bagian 1
Tujuan
Instruksional
|
|
·
Studi kasus kelas Waktu.
·
Skop kelas dan
mengakses anggota kelas.
·
Fungsi akses dan
fungsi utilitas.
·
Konstruktor dengan
argumen default.
|
·
Destruktor.
·
Kapan konstruktor
dan destruktor dipanggil.
·
Mengembalikan
sebuah referensi ke suatu anggota data private.
|
1.1 Introduksi
Pada bab ini, akan didiskusikan tentang
kelas. Akan digunakan kelas Waktu
pada bab ini dan bab berikutnya. Kelas Waktu
akan menyajikan beberapa fitur penting tentang pemrograman berorientasi objek.
Contoh ini juga mendemonstrasikan konsep rekayasa perangkat-lunak C++ yang
penting.
Selanjutnya, akan didiskusikan skop
kelas dan relasi antar anggota kelas. Akan didemonstrasikan bagaimana kode
klien dapat mengakses anggota public
suatu kelas melalui tiga cara: lewat nama objek, lewat referensi ke sebuah
objek, atau lewat pointer yang menunjuk ke suatu objek. Seperti yang akan Anda
lihat, nama dan referensi dapat digunakan dengan operator penyeleksi anggota
dot (.) untuk mengakses anggota public,
dan pointer dapat digunakan dengan operator penyeleksi anggota tanda panah
(->).
Selanjutnya akan dipelajari tentang
fungsi akses yang dapat membaca atau menampilkan data di dalam sebuah objek.
Kegunaan umum dari fungsi akses adalah untuk menguji kebenaran atau
ketidak-benaran kondisi. Fungsi semacam itu dikenal dengan fungsi predikat.
Akan didemonstrasikan juga fungsi utilitas (yang dikenal juga dengan fungsi
pembantu), yaitu sebuah fungsi anggota private
yang mendukung operasi dari fungsi anggota public
suatu kelas, tetapi fungsi pembantu ini tidak dimaksudkan untuk digunakan oleh
klien atau pengguna kelas.
Pada kelas Waktu kedua, akan didemonstrasikan bagaimana melewatkan argumen
kepada konstruktor dan ditunjukkan bagaimana argumen default dapat digunakan di
dalam suatu konstruktor untuk memampukan klien dalam menginisialisasi objek
menggunakan berbagai argumen. Selanjutnya, akan didiskusikan fungsi anggota
spesial yang dinamakan destruktor, yang merupakan bagian dari kelas, dan
digunakan untuk melakukan “penghentian”
dan “operasi bersih-bersih” pada
sebuah objek sebelum objek tersebut dihancurkan. Kemudian akan didemonstrasikan
urutan pemanggilan konstruktor dan destruktor, karena keberhasilan program Anda
bergantung pada penggunaan objek-objek terinisialisasi yang belum dihancurkan.
Contoh terakhir dari studi kasus Waktu pada bab ini menunjukkan sebuah
praktek pemrograman berbahaya dimana di dalamnya sebuah fungsi anggota
menghasilkan nilai balik berupa sebuah referensi ke data private. Akan didiskusikan bagaimana hal ini merusak enkapsulasi
suatu kelas dan mengijinkan kode klien untuk secara langsung mengakses data di
dalam objek. Contoh terakhir ini menunjukkan bahwa objek sesama kelas dapat
ditugaskan dari satu objek ke objek lainnya menggunakan penugasan keanggotaan
default, yang menyalin anggota-anggota data di dalam objek di sisi kanan
penugasan ke dalam anggota-anggota data di dalam objek di sisi kiri penugasan.
1.2 Studi Kasus Kelas Waktu
Contoh pertama yang disajikan (Gambar
1.1 – 1.3) menciptakan kelas Waktu
dan sebuah program untuk menguji kelas tersebut. Akan didemonstrasikan konsep
penting rekayasa perangkat-lunak C++, menggunakan preprosesor di dalam header.
Karena kelas didefinisikan hanya sekali, penggunaan preprosesor semacam itu
mencegah error pendefinisian-jamak.
Gambar 1.1 Definisi Kelas Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Gambar 1.1: Waktu.h
// Definisi kelas Waktu.
// Fungsi anggota didefinisikan di dalam
Waktu.cpp
// mencegah penyertaan jamak header
#ifndef
WAKTU_H
#define
WAKTU_H
// Definisi kelas Waktu
class Waktu
{
public:
Waktu(); // konstruktor
void setWaktu( int, int,
int ); // menetapkan jam, menit, dan detik
void tampilUniversal(); //
menampilkan waktu dalam format universal
void tampilStandard(); // menampilkan
waktu dalam format standard
private:
int jam; // 0 - 23 (format 24-jam)
int menit; // 0 - 59
int detik; // 0 - 59
}; // akhir dari kelas Waktu
#endif
|
Definisi Kelas
Waktu
Definisi kelas (Gambar 1.1) memuat
beberapa prototipe (baris 13-16) untuk fungsi anggota kelas Waktu, yaitu setWaktu, tampilUniversal,
dan tampilStandard. Definisi kelas
ini juga menyertakan anggota integer private,
yaitu jam, menit, dan detik. Anggota
data private kelas Waktu hanya dapat
diakses oleh keempat fungsi anggota public-nya.
Pada Gambar 1.1, definisi kelas diapit
di dalam pembungkus preprosesor berikut (baris 6, 7, dan 32):
#ifndef WAKTU_H
#define WAKTU _H
...
#endif
Ketika Anda membangun program yang
lebih besar, definisi dan deklarasi lain juga ditempatkan di dalam header.
Pembungkus preprosesor tersebut mencegah kode yang berada di antara #ifndef (“if not defined”) dan #endif
untuk disertakan jika nama WAKTU_H
telah didefinisikan. Jika header tersebut tidak disertakan sebelumnya di dalam
sebuah file, maka nama WAKTU_H
didefinisikan menggunakan direktif #define
dan statemen header dicantumkan.
Fungsi Anggota
Kelas Waktu
Pada Gambar 1.2, konstruktor Waktu (baris 11-14) menginisialisasi
anggota-anggota data dengan 0. Nilai tak-valid tidak bisa disimpan di dalam
anggota data objek Waktu, karena
konstruktor dipanggil ketika objek Waktu
diciptakan, dan semua usaha oleh klien untuk memodifikasi anggota data akan
diperiksa oleh fungsi setWaktu
(sebentar lagi akan didiskusikan). Adalah hal penting untuk mengetahui bahwa
Anda dapat mendefinisikan beberapa konstruktor teroverload untuk suatu kelas.
Gambar 1.2 Definisi Fungsi Anggota untuk Kelas
Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
// Gambar. 1.2: Waktu.cpp
// Definisi fungsi anggota untuk kelas
Waktu.
#include <iostream>
#include <iomanip>
#include <stdexcept> // untuk kelas eksepsi
invalid_argument
#include "Waktu.h" // menyertakan definisi kelas
Waktu dari Waktu.h
using namespace std;
// konstruktor Waktu menginisialisasi setiap
anggota data dengan nol.
Waktu::Waktu()
{
jam
= menit = detik = 0;
} // akhir dari konstruktor Waktu
// menetapkan Waktu baru menggunakan waktu
universal
void Waktu::setWaktu( int h, int m, int
s )
{
// memvalidasi jam, menit, dan detik
if ( ( h >= 0 && h < 24
) && ( m >= 0 && m < 60 ) &&
( s >= 0 && s < 60 ) )
{
jam = h;
menit = m;
detik = s;
} // akhir dari if
else
throw
invalid_argument(
"jam,
menit dan/atau detik di luar rentang" );
} // akhir dari fungsi setWaktu
//
menampilkan Waktu dalam format universal (HH:MM:SS)
void Waktu::tampilUniversal()
{
cout << setfill( '0' ) << setw( 2 ) << jam <<
":"
<< setw( 2 ) << menit <<
":" << setw( 2 ) << detik;
} // akhir dari fungsi tampilUniversal
//
menampilkan Waktu dalam format standard (HH:MM:SS AM atau PM)
void Waktu::tampilStandard()
{
cout << ( ( jam == 0 || jam == 12 ) ? 12 : jam % 12 ) << ":"
<< setfill( '0' ) << setw( 2 ) << menit <<
":" << setw( 2 )
<< detik << ( jam < 12 ? " AM" : " PM"
);
} // akhir dari fungsi tampilStandard
|
Kecuali anggota data static const int, anggota data suatu
kelas tidak bisa diinisialisasi dimana anggota tersebut dideklarasikan di dalam
tubuh kelas. Meskipun hal itu sebenarnya diijinkan, tetapi sangat
direkomendasikan bahwa anggota data diinisialiasi oleh konstruktor kelas. Pada
kasus ini, anggota data juga dapat ditugasi nilai oleh fungsi setWaktu.
Fungsi Anggot
setWaktu dan Pelemparan Eksepsi
Fungsi setWaktu (baris 17-30) merupakan sebuah fungsi public yang mendeklarasikan tiga parameter int dan menggunakannya
untuk menetapkan waktu. Baris 20-21 menguji setiap argumen untuk menentukan
apakah setiap nilai berada di dalam rentang atau tidak, dan, jika tidak, baris
23-25 menugaskan nilai-nilai tersebut kepada anggota data jam, menit, dan detik. Nilai jam harus lebih dari atau sama dengan 0 dan kurang dari 24, karena
format waktu universal merepresentasikan jam sebagai integer dari 0 sampai 23
(misalnya 1 PM adalah jam 13 dan 11 PM adalah jam 23; tengah malam adalah jam
0). Kedua menit dan detik harus lebih dari atau sama dengan
0 dan kurang dari 60. Untuk nilai-nilai yang berada di luar rentang tersebut, setWaktu akan melemparkan sebuah eksepsi
bertipe invalid_argument (baris
28-29), yang akan memberitahu kode klien bahwa argumen tak-valid telah
diterima. Anda bisa menggunakan try...catch
untuk menangkap eksepsi dan mencoba memulihkan kesalahan tersebut, yang akan
dilakukan pada Gambar 1.3. Statemen throw
(baris 28-29) menciptakan sebuah objek baru bertipe invalid_argument. Kurung yang mengikuti nama kelas mengindikasikan
pemanggilan terhadap konstruktor invalid_argument
yang mengijinkan Anda untuk menspesifikasi string pesan error. Setelah objek
eksepsi diciptakan, statemen throw
menghentikan fungsi setWaktu dan
eksepsi dikembalikan kepada kode yang mencoba menetapkan waktu (yang tak-valid)
tersebut.
Fungsi Anggot
tampilUniversal
Fungsi tampilUniversal (baris 33-37 pada Gambar 1.2) tidak mengambil
argumen apapun dan menampilkan waktu dalam format universal, yang memuat tiga
pasang dijit yang dipisahkan oleh titik-dua untuk jam, menit, dan detik.
Sebagai contoh, jika waktu adalah 1:30:07 PM, fungsi tampilUniversal akan menghasilkan 13:30:07. Baris 35 menggunakan
manipulator aliran terparameterisasi setfill
untuk menspesifikasi karakter yang ditampilkan ketika sebuah integer
ditampilkan pada suatu bidang yang lebih lebar dari jumlah dijit di dalam
nilai. Secara default, karakter pengisi disisipkan di sisi kiri dijit. Pada
contoh ini, jika menit adalah 2, maka akan ditampilkan sebagai 02, karena
karakter pengisi ditetapkan sebagai 0 (‘0’). Jika angka yang ditampilkan
memenuhi bidang yang dispesifikasi, maka karakter pengisi tidak akan
ditampilkan. Begitu karakter pengisi dispesifikasi dengan setfill, maka hal itu berlaku untuk semua nilai yang akan
ditampilkan pada bidang yang lebih lebar dari nilai tersebut. Hal ini
berlawanan dengan setw, yang hanya
berlaku pada nilai berikutnya yang akan ditampilkan.
Fungsi Anggot
tampilStandard
Fungsi tampilStandard (baris 40-45) tidak mengambil argumen apapun dan
menampilkan waktu dalam format standard, yang memuat jam, menit, dan detik yang dipisahkan oleh titik-dua dan
diikuti oleh indikator AM atau PM (misalnya, 1:27:06 PM). Seperti fungsi tampilUniversal, fungsi tampilStandard menggunakan setfill(‘0’) untuk memformat menit dan detik sebagai dua dijit nilai dengan kepala nol jika diperlukan.
Baris 42 menggunakan operator kondisional (?:) untuk menentukan nilai jam yang akan ditampilkan, jika jam bernilai 0 atau 12 (AM atau PM),
maka jam akan ditampilkan sebagai 12;
sebaliknya, jam akan ditampilkan sebagai suatu nilai dari 1 sampai 11. Operator
kondisional pada baris 44 menentukan apakah AM atau PM yang akan ditampilkan.
Mendefinisikan
Fungsi Anggota di luar Definisi Kelas
Meskipun sebuah fungsi anggota yang
dideklarasikan di dalam definisi kelas dapat didefinisikan di luar definisi
kelas tersebut, fungsi anggota tersebut masih berada di dalam skop kelas.
Namanya dikenal oleh anggota-anggota lain di dalam kelas tersebut. Jika sebuah
fungsi anggota didefinisikan di dalam tubuh suatu definisi kelas, maka ia
secara implisit dideklarasikan inline.
Menggunakan
Kelas Waktu
Setelah didefinisikan, Waktu dapat dipakai sebagai sebuah tipe
di dalam deklarasi sebagai berikut:
Time pagi; // objek bertipe Waktu
Time arrayWaktu[ 5 ]; // array yang
memuat 5 objek Waktu
Time &sarapan = pagi; // referensi ke
sebuah objek Waktu
Time *waktuPtr = &sarapan; // pointer yang menunjuk
ke sebuah objek Waktu
Gambar 1.3 menggunakan kelas Waktu. Baris 10 menginstansiasi sebuah
objek Waktu yang dinamakan t. Ketika objek tersebut diinstansiasi,
konstruktor Waku dipanggil untuk
menginisialisasi setiap anggota data private
dengan 0. Kemudian baris 14 dan 16 menampilkan waktu dalam format universal dan
format standard untuk menegaskan bahwa setiap anggota telah diinisialisasi
dengan benar. Baris 18 menetapkan waktu baru dengan memanggil fungsi setWaktu, dan baris 22 dan baris 24
menampilkan waktu kembali dalam dua format.
Gambar 1.3 Program Menguji Kelas Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
// Gambar 1.3: gambar1_03.cpp
// Program untuk menguji kelas Waktu.
// PERHATIAN: File ini harus dikompilasi
dengan Waktu.cpp.
#include <iostream>
#include "Waktu.h" // menyertakan
definisi kelas Waktu dari Waktu.h
using namespace std;
int main()
{
Waktu t; // menginstansiasi objek t dari
kelas Waktu
//
menampilkan nilai-nilai awal objek t
cout << "Waktu universal awal
adalah ";
t.tampilUniversal(); // 00:00:00
cout << "\nWaktu standard awal
adalah ";
t.tampilStandard(); // 12:00:00 AM
t.setWaktu(
13, 27, 6 ); // mengubah waktu
// menampilkan nilai-nilai baru objek t
cout << "\n\nWaktu universal
setelah setWaktu adalah ";
t.tampilUniversal(); // 13:27:06
cout << "\nWaktu standard
setelah setWaktu adalah ";
t.tampilStandard(); // 1:27:06 PM
// mencoba untuk menetapkan waktu dengan
nilai tak-valid
try
{
t.setWaktu( 99, 99, 99 ); // semua nilai
diluar rentang
} // akhir dari try
catch ( invalid_argument &e )
{
cout << "Eksepsi: "
<< e.what() << endl << endl;
} // akhir dari catch
// menampilkan
nilai-nilai objek t setelah menspesifikasi nilai tak-valid
cout << "\n\nSetelah mencoba
menetapkan nilai tak-valid:"
<< "\nWaktu universal:
";
t.tampilUniversal(); // 00:00:00
cout << "\nWaktu standard:
";
t.tampilStandard(); // 12:00:00 AM
cout << endl;
} // akhir dari main
|
Waktu universal awal adalah 00:00:00
Waktu standard awal adalah 12:00:00 AM
Waktu universal setelah setWaktu adalah 13:27:06
Waktu standard setelah setWaktu adalah 1:27:06 PM
Eksepsi terjadi: jam, menit dan/atau detik di luar rentang
Setelah mencoba menetapkan nilai tak-valid:
Waktu universal: 13:27:06
Waktu standard: 1:27:06 PM
Memanggil
setWaktu dengan Nilai Tak-Valid
Untuk mengilustrasikan bahwa metode setWaktu memvalidasi argumennya, baris
29 memanggil setWaktu dengan argumen
tak-valid 99 untuk jam, menit, dan detik. Statemen ini ditempatkan di dalam sebuah blok try (baris 27-30) untuk berjaga-jaga
apabila setWaktu melemparkan eksepsi invalid_argument. Ketika ini terjadi,
eksepsi ditangkap pada baris 31-34 dan baris 33 menampilkan pesan error eksepsi
dengan memanggil fungsi anggota what.
Baris 37-41 menampilkan waktu kembali dalam dua format untuk memastikan bahwa setWaktu tidak mengubah waktu ketika
argumen tak-valid disuplai.
1.3 Skop Kelas dan Mengakses Anggota
Kelas
Anggota data suatu kelas (variabel yang
dideklarasikan di dalam definisi kelas) dan anggota kelas (fungsi yang
dideklarasikan di dalam definisi kelas) berada di dalam skop kelas. Fungsi
non-anggota didefinisikan dengan skop namespace
global.
Dengan skop kelas, anggota kelas dapat
diakses oleh semua fungsi anggota kelas tersebut dan dapat direferensi dengan
nama. Di luar skop kelas, anggota public
suatu kelas dapat direferensi melalui nama objek, melalui referensi ke objek,
atau melalui pointer yang menunjuk ke objek.
Fungsi anggota suatu kelas dapat dioverload, tetapi hanya oleh fungsi
anggota lain dari kelas tersebut. Untuk mengoverload fungsi anggota, Anda hanya
perlu menyediakan prototipe di dalam definisi kelas untuk setiap versi fungsi
teroverload dan menyediakan definisi
fungsi terpisah untuk setiap versi fungsi teroverload. Ini juga berlaku untuk konstruktor kelas.
Variabel yang dideklarasikan di dalam
sebuah fungsi anggota memiliki skop lokal dan hanya dikenal oleh fungsi
tersebut. Jika sebuah fungsi anggota mendefinisikan suatu variabel dengan nama
sama dengan suatu variabel dengan skop kelas, maka variabel skop kelas tersebut
disembunyikan oleh variabel skop lokal. Jadi, variabel skop kelas tersebut
tidak dikenal di dalam skop lokal. Variabel tersembunyi semacam itu dapat
diakses dengan memberikan nama kelas di depan nama variabel dan menempatkan
operator resolusi skop (::) setelah nama kelas tersebut.
Operator penyeleksi anggota dot (.)
yang ditempatkan setelah nama objek atau ditempatkan setelah sebuah referensi
ke suatu objek dapat dipakai untuk mengakses anggota objek itu. Operator
penyeleksi anggota panah (->) yang ditempatkan setelah setelah sebuah
pointer yang menunjuk ke suatu objek dapat digunakan untuk mengakses anggota
objek tersebut.
Gambar 1.4 menggunakan kelas sederhana
yang dinamakan Hitung (baris 7-24)
dengan anggota data private x bertipe
int (baris 23), fungsi anggota public setX (baris 11-14), dan fungsi anggota public tampil (baris
17-20) untuk mengilustrasikan pengaksesan anggota kelas dengan operator
penyeleksi anggota. Agar lebih sederhana, kelas kecil ini ditempatkan di file
yang sam dengan fungsi main. Baris
28-30 menciptakan tiga variabel yang berkaitan dengan tipe Hitung, yaitu kounter
(sebuah objek Hitung), kounterPtr (sebuah pointer yang menunjuk
ke objek Hitung), dan kounterRef (sebuah referensi ke sebuah
objek Hitung). Pada baris 33-34 dan
37-38, perhatikan bahwa program memanggil fungsi anggota setX dan tampil dengan
menggunakan operator penyeleksi anggota dot (.) yang diawali dengan nama objek
(kounter) atau dengan referensi ke
objek (kounterRef, yang merupakan
nama alias bagi kounter). Sama halnya, baris 41-42 mendemonstrasikan bahwa
program dapat memanggil fungsi setX
dan tampil dengan menggunakan suatu
pointer (kounterPtr) dan operator
penyeleksi anggota panah (->).
Gambar 1.4 Mendemonstrasikan . dan ->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
// Gambar 1.4: gambar1_04.cpp
// Mendemonstrasikan operator pengakses
anggota kelas . dan ->
#include <iostream>
using namespace std;
// definisi kelas Hitung
class Hitung
{
public: // data public berbahaya
// menetapkan nilai untuk anggota data
private x
void setX( int nilai )
{
x = nilai;
} // akhir dari fungsi setX
// menampilkan nilai dari anggota data
private x
void tampil()
{
cout << x << endl;
} // akhir dari fungsi tampil
private:
int
x;
}; // akhir dari kelas Hitung
int main()
{
Hitung kounter; // menciptakan
objek kounter
Hitung *kounterPtr =
&kounter; // menciptakan pointer ke kounter
Hitung &kounterRef = kounter;
// menciptakan referensi ke kounter
cout
<< "Menetapkan x menjadi 1 dan menampilkannya menggunakan
nama objek: ";
kounter.setX( 1 ); //
menetapkan anggota data x menjadi 1
kounter.tampil(); // memanggil
fungsi anggota tampil
cout
<< "Menetapkan x menjadi 2 dan menampilkannya menggunakan
referensi ke objek: ";
kounterRef.setX( 2 ); //
menetapkan anggota data menjadi 2
kounterRef.tampil(); //
memanggil fungsi anggota tampil
cout
<< "Menetapkan x menjadi 3 menggunakan pointer ke objek:
";
kounterPtr->setX( 3 ); //
menetapkan anggota data menjadi 3
kounterPtr->tampil(); //
memanggil fungsi anggota tampil
} // akhir dari main
|
Menetapkan
x menjadi 1 dan menampilkannya menggunakan nama objek: 1
Menetapkan
x menjadi 2 dan menampilkannya menggunakan referensi ke objek: 2
Menetapkan x
menjadi 3 dan menampilkannya menggunakan pointer ke objek: 3
1.4 Fungsi Akses dan Fungsi Utilitas
Fungsi akses dapat membaca atau
menampilkan data. Kegunaan lain dari fungsi akses adalah untuk menguji
kebenaran atau kesalahan kondisi. Fungsi ini sering juga dipanggil dengan
fungsi predikat. Salah satu contoh dari fungsi predikat adalah fungsi isEmpty untuk sembarang kontainer,
seperti vector. Program dapat menguji
isEmpty sebelum mencoba membaca item
lain dari objek kontainer. Fungsi predikat isFull
dapat menguji kontainer untuk menentukan apakah objek tersebut penuh atau
tidak. Fungsi predikat untuk kelas Waktu
yang bisa Anda tulis adalah isAM dan isPM.
Program pada Gambar 1.5 – 1.7
mendemonstrasikan kegunaan fungsi utilitas (yang juga dipanggil dengan fungsi
pembantu). Fungsi utilitas bukan bagian dari antarmuka public suatu kelas; tetapi, ia menjadi fungsi anggota private yang mendukung operasi fungsi
anggota lain di dalam kelas. Fungsi utilitas tidak dimaksudkan untuk digunakan
oleh kode klien.
Kelas PekerjaPemasaran (Gambar 1.5) mendeklarasikan sebuah array yang
memuat jumlah pemasaran selama 12 bulan (baris 17), beberapa prototipe untuk
konstruktor kelas, dan fungsi anggota yang memanipulasi array.
Gambar 1.5 Definisi Kelas PekerjaPemasaran
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// Gambar 1.5: PekerjaPemasaran.h
// Definisi kelas PekerjaPemasaran.
// Fungsi anggota didefinisikan di dalam
PekerjaPemasaran.cpp.
#ifndef PEKERJAPEMASARAN_H
#define PEKERJAPEMASARAN_H
class PekerjaPemasaran
{
public:
static const int bulanPerTahun = 12;
// bulan di dalam setahun
PekerjaPemasaran(); // konstruktor
void getPemasaranDariPengguna(); // memasukkan pemasaran dari papanketik
void setPemasaran( int, double
); // menetapkan pemasaran untuk bulan tertentu
void tampilPemasaranTahunan(); // menyimpulkan dan menampilkan pemasaran
private:
double
totalPemasaranTahunan(); // prototipe untuk fungsi utilitas
double
pemasaran[ bulanPerTahun ]; // nilai pemasaran 12 bulan
}; // akhir dari kelas PekerjaPemasaran
#endif
|
Pada Gambar 1.6, konstruktor PekerjaPemasaran (baris 9-13)
menginisialisasi array pemasaran
dengan nol. Fungsi anggota public
setPemasaran (baris 30-37) menetapkan angka pemasaran untuk satu bulan di
dalam array pemasaran. Fungsi anggota
public tampilPemasaranTahunan (baris 40-45) menampilkan total pemasaran
untuk 12 bulan terakhir. Fungsi utilitas private
totalPemasaranTahunan (baris 48-56)
menghitung total nilai pemasaran selama 12 bulan untuk ditampilkan oleh tampilPemasaranTahunan. Fungsi tampilPemasaranTahunan mengedit nilai
pemasaran dalam format moneter.
Gambar 1.6 Definisi Kelas PekerjaPemasaran
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
// Gambar 1.6: PekerjaPemasaran.cpp
// Definisi fungsi anggota kelas
PekerjaPemasaran.
#include <iostream>
#include <iomanip>
#include "PekerjaPemasaran.h" // menyertakan definisi kelas PekerjaPemasaran
using namespace std;
// menginisialisasi elemen-elemen array
pemasaran menjadi 0.0
PekerjaPemasaran::PekerjaPemasaran()
{
for ( int i = 0; i <
bulanPerTahun; ++i )
pemasaran[
i ] = 0.0;
} // akhir dari konstruktor PekerjaPemasaran
// mendapatkan 12 angka pemasaran dari
pengguna dengan papanketik
void PekerjaPemasaran::getPemasaranDariPengguna()
{
double angkaPemasaran;
for ( int i = 1; i <=
bulanPerTahun; ++i )
{
cout << "Masukkan angka
pemasaran untuk bulan " << i << ": ";
cin >> angkaPemasaran;
setPemasaran( i, angkaPemasaran );
} // akhir dari for
} //
akhir dari fungsi getPemasaranDariPengguna
// menetapkan satu dari 12 angka pemasaran bulanan;
fungsi mengurangkan
// satu dari nilai bulan untuk kepentingan
subskript
void PekerjaPemasaran::setPemasaran( int bulan,
double jumlah )
{
// menguji validitas bulan dan jumlah
if ( bulan >= 1 && bulan
<= bulanPerTahun && jumlah > 0 )
pemasaran[ bulan - 1 ] = jumlah; // mengubah subskript menjadi 0-11
else // bulan atau jumlah tak-valid
cout << "Angka pemasaran dan
jumlah tak-valid" << endl;
} // akhir dari fungsi setPemasaran
// menampilkan total
pemasaran tahunan (dengan bantuan fungsi utilitas)
void PekerjaPemasaran::tampilPemasaranTahunan()
{
cout << setprecision( 2 ) <<
fixed
<< "\nTotal pemasaran
tahunan: Rp. "
<< totalPemasaranTahunan() << endl; // memanggil fungsi utilitas
} // akhir dari fungsi
tampilPemasaranTahunann
// fungsi utilitas private untuk menghitung
total pemasaran tahunan
double PekerjaPemasaran::totalPemasaranTahunan()
{
double
total = 0.0; // menginisialisasi total
for
( int i = 0; i < bulanPerTahun; ++i ) // total hasil pemasaran
total
+= pemasaran[ i ]; // menjumlahkan pemasaran bulan
ke-i kepada total
return
total;
} // akhir dari fungsi totalPemasaranTahunan
|
Pada Gambar 1.7, perhatikan bahwa
fungsi main hanya mencantumkan deretan pemanggilan fungsi anggota, tidak
terdapat statemen kendali. Logika pemanipulasian array pemasaran secara utuh dienkapsulasi di dalam fungsi anggota.
Gambar 1.7 Mendemonstrasikan Fungsi Utilitas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// Gambar 1.7: gambar1_07.cpp
// Mendemonstrasikan fungsi utilitas.
// Kompilasi program ini dengan
PekerjaPemasaran.cpp
// menyertakan definisi kelas
PekerjaPemasaran dari PekerjaPemasaran.h
#include "PekerjaPemasaran.h"
int main()
{
PekerjaPemasaran s; // menciptakan objek
PekerjaPemasaran (s)
s.getPemasaranDariPengguna();
s.tampilPemasaranTahunan();
} // akhir dari main
|
Masukkan
jumlah pemasaran untuk bulan 1: 5314.76
Masukkan
jumlah pemasaran untuk bulan 2: 4292.38
Masukkan
jumlah pemasaran untuk bulan 3: 4589.83
Masukkan
jumlah pemasaran untuk bulan 4: 5534.03
Masukkan
jumlah pemasaran untuk bulan 5: 4376.34
Masukkan
jumlah pemasaran untuk bulan 6: 5698.45
Masukkan
jumlah pemasaran untuk bulan 7: 4439.22
Masukkan
jumlah pemasaran untuk bulan 8: 5893.57
Masukkan
jumlah pemasaran untuk bulan 9: 4909.67
Masukkan
jumlah pemasaran untuk bulan 10: 5123.45
Masukkan
jumlah pemasaran untuk bulan 11: 4024.97
Masukkan jumlah
pemasaran untuk bulan 12: 5923.92
Total pemasaran
tahunan: Rp. 60120.59
1.5 Studi Kasus Kelas Waktu:
Konstruktor dengan Argumen Default
Program pada Gambar 1.8 - 1.10
memperbaiki kelas Waktu sehingga
dapat mendemonstrasikan bagaimana argumen secara implisit dilewatkan kepada
sebuah konstruktor. Konstruktor yang didefinisikan pada Gambar 1.2
menginisialisasi jam, menit, dan detik dengan 0. Sama seperti fungsi, konstruktor dapat
menspesifikasi argumen default. Baris 13 pada Gambar 1.8 mendeklarasikan
konstruktor Waktu untuk menyertakan
argumen-argumen default, yang menspesifikasi nilai default 0 untuk setiap
argumen yang dilewatkan kepada konstruktor. Pada Gambar 1.9, baris 10-13
mendefinisikan versi baru dari konstruktor Waktu
yang menerima nilai-nilai untuk parameter jam,
menit, dan detik yang akan digunakan untuk menginisialisasi anggota data private jam, menit, dan detik. Kelas Waktu menyediakan beberapa fungsi set dan get untuk setiap
anggota data. Konstruktor Waktu
sekarang memanggil setWaktu, yang
memanggil setJam, setMenit, dan setDetik untuk memvalidasi dan menugaskan nilai-nilai kepada
anggota-anggota. Argumen default kepada konstruktor memastikan bahwa, meski
jika tidak ada nilai yang disediakan di dalam pemanggilan sebuah konstruktor,
konstruktor masih tetap menginisialisasi anggota data. Sebuah konstruktor yang
menetapkan nilai default untuk semua argumennya disebut dengan konstruktor
default. Konstruktor default dapat dipanggil tanpa argumen. Hanya boleh
terdapat satu konstruktor default di dalam setiap kelas.
Gambar 1.8 Definisi Kelas Waktu dengan Konstruktor
Default
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// Gambar 1.8: Waktu.h
// Definisi kelas Waktu yang memuat
konstruktor default.
// Fungsi anggota didefinisikan di dalam
Waktu.cpp
// mencegah penyertaan jamak header
#ifndef WAKTU_H
#define WAKTU_H
// Definisi kelas Waktu
class Waktu
{
public:
Waktu( int = 0, int = 0, int = 0 ); //
konstruktor default
// fungsi set
void setWaktu( int, int,
int ); // menetapkan jam, menit, dan detik
void setJam( int ); //
menetapkan jam (setelah validasi)
void setMenit( int ); //
menetapkan menit (setelah validasi)
void setDetik( int ); //
menetapkan detik (setelah validasi)
// fungsi get
int getJam(); // menghasilkan jam
int getMenit(); // menghasilkan menit
int getDetik(); // menghasilkan detik
void tampilUniversal(); //
menampilkan waktu dalam format universal
void tampilStandard(); // menampilkan
waktu dalam format standard
private:
int jam; // 0 - 23 (format 24-jam)
int menit; // 0 - 59
int detik; // 0 - 59
}; // akhir dari kelas Waktu
#endif
|
Pada Gambar 1.9, baris 12, konstruktor memanggil fugsi anggota setWaktu dengan nilai-nilai yang
dilewatkan kepada konstruktor (nilai-nilai default). Fungsi setWaktu memanggil setJam untuk memastikan bahwa nilai yang disuplai untuk jam berada di dalam rentang 0-23,
kemudian memanggil setMenit dan setDetik untuk memastikan bahwa nilai
yang disuplai untuk menit dan detik berada di dalam rentang 0-59.
Fungsi setJam (baris 24-30), setMenit (baris 33-39), dan setDetik (baris 42-48) masing-masing
sebuah eksepsi jika argumen yang diterima berada di luar rentang yang
diijinkan.
Gambar 1.9 Definisi Fungsi Anggota Kelas Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
// Gambar. 1.9: Waktu.cpp
// Definisi fungsi anggota untuk kelas
Waktu.
#include <iostream>
#include <iomanip>
#include <stdexcept> // untuk kelas eksepsi
invalid_argument
#include "Waktu.h" // menyertakan
definisi kelas Waktu dari Waktu.h
using namespace std;
// konstruktor Waktu
menginisialisasi setiap anggota data dengan nol.
Waktu::Waktu( int jam, int
menit, int detik )
{
setWaktu(
jam, menit, detik ); // memvalidasi dan menetapkan
waktu
} // akhir dari konstruktor Waktu
// menetapkan nilai Waktu baru menggunakan
waktu universal
void Waktu::setWaktu( int h, int m, int
s )
{
setJam( h ); // menetapkan bidang private
jam
setMenit( m ); // menetapkan bidang private
menit
setDetik( s ); // menetapkan bidang private
detik
} // akhir dari fungsi setWaktu
// menetapkan nilai jam
void Waktu::setJam( int h )
{
if ( h >= 0 && h < 24 )
jam = h;
else
throw invalid_argument( "jam
harus dalam rentang 0-23" );
} // akhir dari fungsi setJam
// menetapkan nilai menit
void Waktu::setMenit( int m )
{
if ( m >= 0 && m < 60 )
menit = m;
else
throw invalid_argument( "menit
harus dalam rentang 0-59" );
} // akhir dari fungsi setMenit
// menetapkan nilai detik
void Waktu::setDetik( int s )
{
if ( s >= 0 && s < 60 )
detik = s;
else
throw invalid_argument( "detik
harus dalam rentang 0-59" );
} // akhir dari fungsi setDetik
// menghasilkan nilai jam
int Waktu::getJam()
{
return jam;
} // akhir dari fungsi getJam
// menghasilkan nilai menit
int Waktu::getMenit()
{
return menit;
} // akhir dari fungsi getMenit
// menghasilkan nilai detik
int Waktu::getDetik()
{
return detik;
} // akhir dari fungsi getDetik
// menampilkan Waktu dalam format universal
(HH:MM:SS)
void Waktu::tampilUniversal()
{
cout << setfill( '0' ) << setw(
2 ) << getJam() << ":"
<< setw( 2 ) << getMenit()
<< ":" << setw( 2 ) << getDetik();
} // akhir dari fungsi tampilUniversal
//
menampilkan Waktu dalam format standard (HH:MM:SS AM atau PM)
void Waktu::tampilStandard()
{
cout << ( ( getJam() == 0 || getJam()
== 12 ) ? 12 : getJam() % 12 ) << ":"
<< setfill( '0' ) << setw( 2 )
<< getMenit() << ":" << setw( 2 )
<< getDetik() << ( getJam()
< 12 ? " AM" : " PM" );
} // akhir dari fungsi tampilStandard
|
Fungsi main pada Gambar 1.10 menginisialisasi lima objek Waktu, yaitu satu dengan tiga argumen
default di dalam pemanggilan konstruktor implisit (baris 10), satu dengan satu
argumen yang dispesifikasi (baris 11), satu dengan dua argumen yang
dispesifikasi (baris 12), satu dengan tiga argumen yang dispesifikasi (baris
13), dan satu dengan tiga argumen tak-valid yang dispesifikasi (baris 38).
Program menampilkan setiap objek dalam format waktu universal dan format waktu
standard. Untuk objek Waktu, t5, pada (baris 38), program menampilkan
pesan error karena argumen konstruktor di luar rentang yang diijinkan.
Gambar 1.10 Mendemonstrasikan Konstruktor Default
untuk Kelas Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
// Gambar 1.10: gambar1_10.cpp
// Mendemonstrasikan konstruktor default
untuk kelas Waktu.
#include <iostream>
#include <stdexcept>
#include "Waktu.h" // menyertakan
definisi kelas Waktu dari Waktu.h
using namespace std;
int main()
{
Waktu t1; // semua argumen
default
Waktu t2( 2 ); // jam
dispesifikasi; menit dan detik default
Waktu t3( 21, 34 ); // jam dan
menit dispesifikasi; detik default
Waktu t4( 12, 25, 42 ); //
jam, menit, dan detik dispesifikasi
cout << "Dikonstruksi dengan:\n\nt1:
semua argumen default\n ";
t1.tampilUniversal(); // 00:00:00
cout << "\n ";
t1.tampilStandard(); // 12:00:00 AM
cout << "\n\nt2: jam
dispesifikasi; menit dan detik default\n ";
t2.tampilUniversal(); // 02:00:00
cout << "\n ";
t2.tampilStandard(); // 2:00:00 AM
cout << "\n\nt3: jam dan menit
dispesifikasi; detik default\n ";
t3.tampilUniversal(); // 21:34:00
cout << "\n ";
t3.tampilStandard(); // 9:34:00 PM
cout << "\n\nt4: jam, menit,
dan detik dispesifikasi\n ";
t4.tampilUniversal(); // 12:25:42
cout << "\n ";
t4.tampilStandard(); // 12:25:42 PM
// mencoba menginisialisasi t5 dengan
nilai-nilai tak-valid
try
{
Waktu t5( 27, 74, 99 ); // semua nilai
tak-valid
} // akhir dari try
catch ( invalid_argument &e )
{
cout << "\n\nEksepsi
ketika menginisialisasi t5: " << e.what() << endl;
} // akhir dari catch
} // akhir dari main
|
Dikonstruksi
dengan:
t1: semua
argumen default
00:00:00
12:00:00 AM
t2:
jam dispesifikasi; menit dan detik default
02:00:00
2:00:00 AM
t3: jam
dan menit dispesifikasi; detik default
21:34:00
9:34:00 PM
t4:
jam, menit, dan detik dispesifikasi
12:25:42
12:25:42 PM
Eksepsi ketika menginisialisasi t5: jam harus
dalam rentang 0-23
Beberapa fungsi set dan get pada kelas Waktu dipanggil melalui tubuh kelas.
Secara khusus, fungsi setWaktu (baris
17-22 pada Gambar 1.9) memanggil fungsi setJam,
setMenit, dan setDetik. Fungsi tampilUniversal
dan tampilStandard memanggil fungsi getJam, getMenit, dan getDetik
pada baris 72-73 dan baris 79-81. Pada setiap kasus, fungsi-fungsi tersebut
mengakses data private kelas secara
langsung.
1.6 Destruktor
Destruktor adalah jenis lain dari
fungsi anggota spesial. Nama destruktor untuk suatu kelas diberikan dengan
karakter ~ yang diikuti nama kelas. Konvensi penamaan ini karena destruktor
adalah komplemen dari konstruktor.
Destruktor suatu kelas dipanggil secara
implisit ketika sebuah objek dihancurkan. Hal ini terjadi, misalnya, ketika
sebuah objek otomatis dihancurkan ketika eksekusi program meninggalkan skop
dimana di dalamnya objek tersebut diinstansiasi.
Meskipun destruktor tidak disediakan
untuk kelas yang disajikan sejauh ini, tetapi sebenarnya setiap kelas memiliki
sebuah destruktor. Jika Anda tidak secara eksplisit menyediakan sebuah
destruktor, kompiler akan menciptakan suatu destruktor kosong.
1.7 Kapan Konstruktor dan Destruktor
Dipanggil
Konstruktor dan destruktor dipanggil
secara implisit oleh kompiler. Urutan pemanggilannya bergantung pada urutan
eksekusi memasuki dan meninggalkan skop dimana objek-objek diinstansiasi.
Secara umum, pemanggilan destruktor dilakukan dengan urutan yang berkebalikan
dengan pemanggilan konstruktor, tetapi seperti yang akan Anda lihat pada Gambar
1.11-1.13, urutan pemanggilan destruktor dapat diubah.
Konstruktor dan
Destruktor untuk Objek dalam Skop Global
Konstruktor dipanggil untuk objek yang
didefinisikan di dalam skop global sebelum sembarang fungsi (termasuk main) pada file tersebut mulai
dieksekusi. Destruktor terkait dipanggil ketika main berhenti dieksekusi. Fungsi exit memaksa sebuah program untuk berhenti segera dan destruktor
bagi objek otomatis tidak dieksekusi. Fugsi ini seringkali dipakai untuk
menghentikan suatu program ketika error dideteksi di dalam masukan atau jika
sebuah file yang akan diproses oleh program tidak bisa dibuka. Fungsi abort melakukan tugas yang sama dengan
fungsi exit, tetapi tanpa mengijinkan
destruktor dari sembarang objek untuk dipanggil. Fungsi abort biasanya dipakai
untuk mengindikasikan penghentian abnormal atas program.
Konstruktor dan
Destruktor untuk Objek Otomatis Lokal
Konstruktor untuk sebuah objek otomatis
lokal dipanggil ketika eksekusi mencapai titik dimana objek tersebut
didefinisikan. Destruktor terkait dipanggil ketika eksekusi meninggalkan skop
objek tersebut (yaitu, blok dimana di dalamnya objek tersebut didefinisikan
telah selesai dieksekusi). Konstruktor dan destruktor untuk objek otomatis
dipanggil setiap kali eksekusi memasuki dan meninggalkan skop objek tersebut.
Destruktor tidak dipanggil untuk objek otomatis jika program berhenti karena
pemanggilan terhadap fungsi exit atau
fungsi abort.
Konstruktor dan
Destruktor untuk Objek Lokal static
Konstruktor untuk sebuah objek lokal static dipanggil hanya sekali, ketika
eksekusi pertama-kali mencapai titik dimana objek tersebut didefinisikan.
Destruktor terkait dipanggil ketika main berhenti atau ketika program memanggil
fungsi exit. Objek global dan objek static dihancurkan dengan urutan yang
berbeda dengan ketika diciptakan. Destruktor tidak dipanggil untuk objek static jika program berhenti karena
pemanggilan fungsi abort.
Mendemonstrasikan
Kapan Konstruktor dan Destruktor Dipanggil
Program pada Gambar 1.11 – 1.13
mendemonstrasikan urutan dimana konstruktor dan destruktor dipanggil untuk
objek-objek kelas CiptakanDanHancurkan
(Gambar 1.11 dan Gambar 1.12). Setiap objek kelas CiptakanDanHancurkan memuat sebuah integer (objekID) dan sebuah string
(pesan) yang digunakan di dalam
keluaran program untuk mengidentifikasi objek (Gambar 1.11 baris 16-17). Contoh
ini murni digunakan untuk tujuan pengajaran dan penjelasan saja. Pada Gambar
1.12, destruktor (baris 21) menentukan apakah objek yang sedang dihancurkan
memiliki objekID 1 atau 6 dan, jika
ya, keluaran menampilkan karakter garis-baru. Baris ini membuat keluaran
program lebih mudah diikuti.
Gambar 1.11 Definisi Kelas CiptakanDanHancurkan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// Gambar 1.11: CiptakanDanHancurkan.h
// Definisi kelas CiptakanDanHancurkan.
// Fungsi-fungsi
anggota didefinisikan di dalam CiptakanDanHancurkan.cpp.
#include <string>
using namespace std;
#ifndef CIPTAKAN_H
#define CIPTAKAN_H
class CiptakanDanHancurkan
{
public:
CiptakanDanHancurkan(
int, string ); // konstruktor
~CiptakanDanHancurkan();
// destruktor
private:
int objekID; // nomor ID untuk objek
string pesan; // pesan mendeskripsikan objek
}; // akhir dari kelas CiptakanDanHancurkan
#endif
|
Gambar 1.12 Definisi Fungsi Anggota Kelas
CiptakanDanHancurkan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// Gambar 1.12: CiptakanDanHancurkan.cpp
// Definisi fungsi anggota kelas
CiptakanDanHancurkan.
#include <iostream>
#include "CiptakanDanHancurkan.h" //menyertakan definisi kelas CiptakanDanHancurkan
using namespace std;
// konstruktor
CiptakanDanHancurkan::CiptakanDanHancurkan(
int ID, string pesanString )
{
objekID
= ID; // menetapkan nomor ID objek
pesan
= pesanString; // menetapkan pesan deskriptif objek
cout
<< "Objek " << objekID << " konstruktor
dipanggil "
<<
pesan << endl;
} // akhir dari CiptakanDanHancurkan
// destruktor
CiptakanDanHancurkan::~CiptakanDanHancurkan()
{
// menampilkan garis-baru untuk objek tertentu; agar
lebih mudah dibaca
cout
<< ( objekID == 1 || objekID == 6 ? "\n" : "" );
cout
<< "Objek " << objekID << " destruktor
dipanggil "
<<
pesan << endl;
} // akhir dari destruktor
~CiptakanDanHancurkan
|
Gambar 1.13 mendefinisikan objek pertama (baris 10) di dalam skop global.
Konstruktornya sebenarnya dipanggil sebelum sembarang statemen di dalam main
dieksekusi dan destruktornya dipanggil setelah program berhenti dan setelah
destruktor untuk semua objek dipanggil.
Fungsi main (baris 12-23) mendeklarasikan tiga objek. Objek kedua (baris 15) dan keempat (baris 21) merupakan objek
otomatis lokal, dan objek ketiga
(baris 16) adalah sebuah objek lokal static.
Konstruktor bagi tiap objek ini dipanggil ketika eksekusi meraih titik dimana
objek tersebut dideklarasikan. Destruktor bagi objek keempat kemudian objek kedua
dipanggil (urutan pemanggilan destruktor berkebalikan dengan urutan pemanggilan
konstruktor) ketika eksekusi mencapai akhir main.
Karena objek ketiga adalah static, ia tetap ada sampai program
berhenti. Destruktor untuk objek ketiga
dipanggil sebelum destruktor untuk objek global pertama dipanggil, tetapi setelah semua objek lainnya dihancurkan.
Fungsi ciptakan (baris 26 – 33) mendeklarasikan tiga objek; objek kelima (baris 29) dan objek ketujuh (baris 31) sebagai objek
otomatis lokal, dan objek keenam
(baris 30) sebagai objek lokal static.
Destruktor untuk objek ketujuh kemudian untuk objek kelima dipanggil (urutan
pemanggilan destruktor berkebalikan dengan urutan pemanggilan konstruktor)
ketika fungsi ciptakan berhenti
dieksekusi. Karena objek keenam
adalah static, maka ia tetap ada
sampai program berhenti. Destruktor untuk objek keenam dipanggil sebelum destruktor untuk objek ketiga dan pertama, tetapi setelah semua objek dihancurkan.
Gambar 1.13 Mendemonstrasikan Urutan Pemanggilan Konstruktor dan Destruktor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// Gambar 1.13: gambar1_13.cpp
// Mendemonstrasikan urutan pemanggilan
konstruktor
// dan destruktor.
#include <iostream>
#include "CiptakanDanHancurkan.h" //menyertakan definisi kelas CiptakanDanHancurkan
using namespace std;
void ciptakan( void ); // prototipe
CiptakanDanHancurkan
pertama( 1, "(global sebelum main)" ); //objek
global
int main()
{
cout << "\nFUNGSI MAIN:
EKSEKUSI DIMULAI" << endl;
CiptakanDanHancurkan kedua( 2, "(otomatis lokal di dalam main)" );
static CiptakanDanHancurkan ketiga( 3, "(lokal static di dalam main)" );
ciptakan(); // memanggil fungsi untuk menciptakan objek
cout << "\nFUNGSI MAIN:
EKSEKUSI DIMULAI KEMBALI" << endl;
CiptakanDanHancurkan keempat( 4, "(otomatis
lokal di dalam main)" );
cout << "\nFUNGSI MAIN:
EKSEKUSI BERAKHIR" << endl;
} // akhir dari main
// fungsi untuk menciptakan objek-objek
void ciptakan( void )
{
cout
<< "\nFUNGSI CIPTAKAN: EKSEKUSI DIMULAI" <<
endl;
CiptakanDanHancurkan kelima(
5, "(otomatis lokal
di dalam ciptakan)" );
static CiptakanDanHancurkan keenam(
6, "(lokal static di
dalam ciptakan)" );
CiptakanDanHancurkan ketujuh(
7, "(otomatis lokal
di dalam ciptakan)" );
cout
<< "\nFUNGSI CIPTAKAN: EKSEKUSI BERAKHIR" <<
endl;
} // akhir dari fungsi ciptakan
|
Objek
1 konstruktor dipanggil (global sebelum main)
FUNGSI
MAIN: EKSEKUSI DIMULAI
Objek
2 konstruktor dipanggil (otomatis lokal di dalam main)
Objek
3 konstruktor dipanggil (lokal static di dalam main)
FUNGSI
CIPTAKAN: EKSEKUSI DIMULAI
Objek
5 konstruktor dipanggil (otomatis lokal di dalam ciptakan)
Objek
6 konstruktor dipanggil (lokal static di dalam ciptakan)
Objek
7 konstruktor (otomatis lokal di dalam
ciptakan)
FUNGSI
CIPTAKAN: EKSEKUSI BERAKHIR
Objek
7 destruktor dipanggil (otomatis lokal di dalam ciptakan)
Objek
5 destruktor dipanggil (otomatis lokal di dalam ciptakan)
FUNGSI
MAIN: EKSEKUSI DIMULAI KEMBALI
Objek
4 konstruktor dipanggil (otomatis lokal di dalam main)
FUNGSI
MAIN: EKSEKUSI BERAKHIR
Objek
4 destruktor dipanggil (otomatis lokal di dalam main)
Objek
2 destruktor dipanggil (otomatis lokal di dalam main)
Objek
6 destruktor dipanggil (otomatis lokal di dalam ciptakan)
Objek
3 destruktor dipanggil (lokal static di dalam main)
Objek 1 destruktor
dipanggil (global sebelum main)
1.8 Studi Kasus Kelas Waktu: Nilai Balik Referensi ke Anggota Data private
Referensi ke sebuah objek merupakan
nama alias bagi objek tersebut dan, oleh karena itu, dapat digunakan di sisi
kiri suatu statemen penugasan. Pada konteks ini, referensi merupakan lvalue yang dapat menerima sebuah nilai.
Salah satu cara untuk menggunakan kapabilitas ini adalah dengan menggunakan
suatu fungsi anggota public yang
menghasilkan nilai balik berupa referensi ke sebuah anggota data private. Jika suatu fungsi menghasilkan
nilai balik berupa referensi const,
maka referensi tersebut tidak bisa dipakai sebagai lvalue yang dapat dimodifikasi.
Program pada Gambar 1.14 – 1.16
menggunakan kelas Waktu yang
disederhanakan (Gambar 1.14 dan Gambar 1.15) untuk mendemonstrasikan
pengembalian referensi ke sebuah anggota data private dengan fungsi anggota burukSetJam
(dideklarasikan pada Gambar 1.14, baris 15 dan didefinisikan pada Gambar 1.15,
baris 37-45). Nilai balik berupa referensi semacam itu sebenarnya menjadikan
pemanggilan terhadap fungsi anggota buruksetJam
sebagai alias untuk anggota data private
(jam).
Gambar 1.14 Definisi Kelas Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// Gambar 1.14: Waktu.h
// Definisi kelas Waktu.
// Fungsi anggota didefinisikan di dalam
Waktu.cpp
// mencegah penyertaan jamak header
#ifndef WAKTU_H
#define WAKTU_H
class Waktu
{
public:
Waktu( int = 0, int = 0, int
= 0 ); // konstruktor default
void setWaktu( int, int,
int ); // menetapkan jam, menit, dan detik
int getJam();
int &burukSetJam( int );
// pengembalian referensi yang berbahaya
private:
int jam;
int menit;
int detik;
}; // akhir dari kelas Waktu
#endif
|
Gambar 1.15 Definisi Fungsi Anggota Kelas Waktu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
// Gambar. 1.15: Waktu.cpp
// Definisi fungsi anggota untuk kelas
Waktu.
#include <iostream>
#include "Waktu.h" // menyertakan
definisi kelas Waktu dari Waktu.h
using namespace std;
// konstruktor Waktu menginisialisasi setiap
anggota data private
// dengan nol.
Waktu::Waktu( int jam, int
menit, int detik )
{
setWaktu(
jam, menit, detik ); // memvalidasi dan menetapkan waktu
} // akhir dari konstruktor Waktu
// menetapkan nilai Waktu baru
void Waktu::setWaktu( int h, int m, int
s )
{
// memvalidasi jam, menit, dan detik
if
( ( h >= 0 && h < 24 ) && ( m >= 0 && m <
60 ) &&
(
s >= 0 && s < 60 ) )
{
jam = h;
menit = m;
detik = s;
} //
akhir dari if
else
throw
invalid_argument(
"jam, menit dan/atau detik di luar rentang" );
} // akhir dari fungsi setWaktu
// menghasilkan nilai jam
int Waktu::getJam()
{
return jam;
} // akhir dari fungsi getJam
// teknik
pemrograman buruk: pengembalian referensi yang menunjuk ke anggota data
private.
int &Waktu::burukSetJam( int hh )
{
if
( hh >= 0 && hh < 24 )
jam = hh;
else
throw
invalid_argument( "jam harus dalam rentang 0-23" );
return jam; // nilai
balik referensi BERBAHAYA
} // akhir dari fungsi burukSetJam
|
Gambar 1.16 mendeklarasikan objek Waktu, t, pada baris 10 dan referensi jamRef
(baris 13), yang diinisialisasi dengan referensi yang dijadikan nilai balik
oleh pemanggilan t.burukSetJam(20).
Baris 15 menampilkan nilai dari jamRef.
Ini menunjukkan bagaimana jamRef
merusak enkapusulasi kelas, dimana sembarang statemen di dalam main seharusnya tidak dapat mengakses
anggota private dari suatu kelas.
Selanjutnya, baris 16 menggunakan alias untuk menetapkan nilai jam menjadi 30 (nilai tak-valid) dan
baris 17 menampilkan nilai yang dijadikan nilai balik oleh fungsi getJam untuk menunjukkan bahwa penugasan
suatu nilai kepada jamRef sebenarnya
memodifikasi anggota data private di
dalam objek Waktu, t. Terakhir, baris 21 menggunakan fungsi
burukSetJam untuk memanggil dirinya
sendiri sebagai lvalue dan menugaskan
74 (nilai tak-valid lainnya) kepada referensi yang dijadikan nilai balik oleh
fungsi tersebut. Baris 26 kembali menampilkan nilai balik yang dikembalikan
oleh fungsi getJam untuk menunjukkan
bahwa penugasan suatu nilai akibat pemanggilan fungsi pada baris 21
memodifikasi data private di dalam
objek Waktu, t.
Gambar 1.16 Mendemonstrasikan Referensi ke Anggota
Data private
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
// Gambar 1.16: gambar1_16.cpp
// Mendemonstrasikan sebuah fungsi anggota
public yang
// mengembalikan sebuah referensi ke anggota
data private.
#include <iostream>
#include "Waktu.h" // menyertakan definisi kelas
Waktu
using namespace std;
int main()
{
Waktu t; // menciptakan objek Waktu
// menginisialisasi
jamRef dengan referensi yang dikembalikan oleh burukSetJam
int &jamRef = t.burukSetJam( 20 ); // 20 adalah nilai
valid
cout << "Jam valid sebelum modifikasi: "
<< jamRef;
jamRef = 30; // menggunakan jamRef untuk menetapkan nilai tak-valid
cout << "\nJam tak-valid
setelah modifikasi: " << t.getJam();
// Berbahaya: Pemanggilan fungsi yang
menjadikan nilai balik
// sebuah referensi dapat digunakan sebagai
lvalue!
t.burukSetJam( 12 ) = 74; // menugaskan nilai tak-valid lain kepada jam
cout << "\n\n*************************************************\n"
<< "TEKNIK PEMROGRAMAN YANG
BURUK!!!!!!!!\n"
<< "t.burukSetJam( 12 )
sebagai lvalue, jam tak-valid: "
<< t.getJam()
<< "\n*************************************************"
<< endl;
} // akhir dari main
|
Jam valid sebelum modifikasi:
20
Jam tak-valid setelah modifikasi:30
*************************************************
TEKNIK PEMROGRAMAN YANG BURUK!!!!!!!!
t.burukSetJam( 12 ) sebagai lvalue, jam
tak-valid: 74
*************************************************
1.9 Penugasan Keanggotaan Default
Operator penugasan (=) dapat dipakai
untuk menugaskan sebuah objek kepada objek lainnya sesama tipe. Secara default,
penugasan semacam itu dilakukan dengan penugasan keanggotaan, dimana setiap
anggota data objek di sisi kanan operator penugasan ditugaskan secara
individual ke anggota data yang sama di dalam objek di sisi kiri operator
penugasan. Gambar 1.14-1.18 mendefinisikan kelas Tanggal untuk digunakan pada contoh ini. Baris 18 pada Gambar 1.19
menggunakan penugasan keanggotaan default untuk menugaskan anggota data dari
objek tanggal1 (tipe Tanggal) kepada anggota data objek tanggal2 (tipe Tanggal). Pada kasus ini, anggota bulan dari objek tanggal1
ditugaskan kepada anggota bulan dari
objek tanggal2, anggota hari dari objek tanggal1 ditugaskan kepada anggota hari dari objek tanggal2,
dan anggota tahun dari objek tanggal1 ditugaskan kepada anggota tahun dari objek tanggal2.
Objek dapat dilewatkan sebagai argumen
fungsi dan bisa pula dijadikan nilai balik oleh fungsi. Pelewatan dan
pengembalian nilai balik semacam itu dilakukan menggukanan pelewatan dengan
nilai secara default, dimana salinan dari objek dilewatkan atau dijadikan nilai
balik. Pada kasus semacam itu, C++ menciptakan sebuah objek baru dan
menggunakan konstruktor penyalin untuk menyalin nilai-nilai objek asli ke dalam
objek baru. Untuk setiap kelas, kompiler menyediakan konstruktor penyalin
default yang menyalin setiap anggota dari objek asli.
Gambar 1.17 Definisi Kelas Tanggal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
// Gambar 1.17: Tanggal.h
// Definisi kelas Tanggal dengan operator
inkremen teroverload.
// mencegah pencantuman jamak atas header
#ifndef TANGGAL_H
#define TANGGAL_H
// Definisi kelas Tanggal
class Tanggal
{
public:
Tanggal( int m = 1, int d = 1,
int y = 1900 ); // konstruktor default
void tampil();
private:
int bulan;
int hari;
int tahun;
}; // akhir dari kelas Tanggal
#endif
|
Gambar 1.18 Definisi Fungsi Anggota Kelas Tanggal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// Gambar 1.18: Tanggal.cpp
// Definisi fungsi anggota kelas Tanggal.
#include <iostream>
#include "Tanggal.h" // menyertakan kelas
Tanggal dari Tanggal.h
using namespace std;
// konstruktor Tanggal (seharusnya melakukan
pengecekan rentang)
Tanggal::Tanggal( int m, int
d, int y )
{
bulan = m;
hari = d;
tahun = y;
} // akhir dari konstruktor Tanggal
// menampilkan Tanggal dalam format
mm/dd/yyyy
void Tanggal::tampil()
{
cout << bulan << '/' <<
hari << '/' << tahun;
} // akhir dari fungsi tampil
|
Gambar 1.19 Mendemonstrasikan Penugasan Keanggotaan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Gambar 1.19: gambar1_19.cpp
// Mendemonstrasikan bahwa objek kelas dapat
ditugaskan
// kepada satu sama lain menggunakan
penugasan keanggotaan.
#include <iostream>
#include "Tanggal.h" // menyertakan
definisi kelas Tanggal dari Tanggal.h
using namespace std;
int main()
{
Tanggal tanggal1( 7, 4, 2004 );
Tanggal tanggal2; // tanggal2 default dengan
1/1/2000
cout << "tanggal1 =
";
tanggal1.tampil();
cout << "\tanggal2 = ";
tanggal2.tampil();
tanggal2 = tanggal1; // penugasan keanggotaan default
cout << "\n\nSetelah penugasan
keanggotaan default, tanggal2 = ";
tanggal2.tampil();
cout << endl;
} //
akhir dari main
|
Kesimpulan
Kode klien dapat
mengakses anggota public suatu kelas
melalui tiga cara: lewat nama objek, lewat referensi ke sebuah objek, atau
lewat pointer yang menunjuk ke suatu objek.
Kegunaan umum dari fungsi akses adalah untuk menguji kebenaran atau
ketidak-benaran kondisi. Fungsi semacam itu dikenal dengan fungsi predikat.
Fungsi utilitas
(yang dikenal juga dengan fungsi pembantu) merupakan sebuah fungsi anggota private
yang mendukung operasi dari fungsi anggota public
suatu kelas.
Fungsi pembantu ini tidak
dimaksudkan untuk digunakan oleh klien atau pengguna kelas.
Kecuali anggota data static const
int, anggota data suatu kelas tidak bisa diinisialisasi dimana anggota
tersebut dideklarasikan di dalam tubuh kelas. Meskipun hal itu sebenarnya
diijinkan, tetapi sangat direkomendasikan bahwa anggota data diinisialiasi oleh
konstruktor kelas.
Anggota data suatu kelas (variabel yang dideklarasikan di dalam definisi
kelas) dan anggota kelas (fungsi yang dideklarasikan di dalam definisi kelas)
berada di dalam skop kelas. Fungsi non-anggota didefinisikan dengan skop
namespace global.
Dengan skop kelas, anggota kelas dapat diakses oleh semua fungsi anggota
kelas tersebut dan dapat direferensi dengan nama. Di luar skop kelas, anggota public suatu kelas dapat direferensi
melalui nama objek, melalui referensi ke objek, atau melalui pointer yang
menunjuk ke objek.
Fungsi anggota suatu kelas dapat dioverload,
tetapi hanya oleh fungsi anggota lain dari kelas tersebut. Untuk mengoverload fungsi anggota, Anda hanya
perlu menyediakan prototipe di dalam definisi kelas untuk setiap versi fungsi
teroverload dan menyediakan definisi
fungsi terpisah untuk setiap versi fungsi teroverload. Ini juga berlaku untuk konstruktor kelas.
Konstruktor dan destruktor dipanggil secara implisit oleh kompiler. Urutan
pemanggilannya bergantung pada urutan eksekusi memasuki dan meninggalkan skop
dimana objek-objek diinstansiasi. Secara umum, pemanggilan destruktor dilakukan
dengan urutan yang berkebalikan dengan pemanggilan konstruktor.
Konstruktor dipanggil untuk objek yang didefinisikan di dalam skop global
sebelum sembarang fungsi (termasuk main)
pada file tersebut mulai dieksekusi. Destruktor terkait dipanggil ketika main berhenti dieksekusi. Fungsi exit memaksa sebuah program untuk
berhenti segera dan destruktor bagi objek otomatis tidak dieksekusi.
Konstruktor untuk sebuah objek otomatis lokal dipanggil ketika eksekusi
mencapai titik dimana objek tersebut didefinisikan. Destruktor terkait
dipanggil ketika eksekusi meninggalkan skop objek tersebut (yaitu, blok dimana
di dalamnya objek tersebut didefinisikan telah selesai dieksekusi). Konstruktor
dan destruktor untuk objek otomatis dipanggil setiap kali eksekusi memasuki dan
meninggalkan skop objek tersebut.
Konstruktor untuk sebuah objek lokal static
dipanggil hanya sekali, ketika eksekusi pertama-kali mencapai titik dimana
objek tersebut didefinisikan. Destruktor terkait dipanggil ketika main berhenti
atau ketika program memanggil fungsi exit.
Objek global dan objek static
dihancurkan dengan urutan yang berbeda dengan ketika diciptakan. Destruktor
tidak dipanggil untuk objek static
jika program berhenti karena pemanggilan fungsi abort.
Operator penugasan (=) dapat dipakai untuk menugaskan sebuah objek kepada
objek lainnya sesama tipe. Secara default, penugasan semacam itu dilakukan
dengan penugasan keanggotaan, dimana setiap anggota data objek di sisi kanan
operator penugasan ditugaskan secara individual ke anggota data yang sama di
dalam objek di sisi kiri operator penugasan.
Latihan
1)
Sediakan sebuah konstruktor
yang mampu menggunakan waktu sekarang dari fungsi time dan localtime (yang
dideklarasikan di dalam header C++ STL <ctime>)
untuk menginisialisasi suatu objek dari kelas Waktu.
2)
Ciptakanlah sebuah kelas yang
dinamakan Rasional untuk melakukan
aritmatika terhadap angka pecahan. Tulislah program untuk menguji kelas Anda.
Gunakan variabel integer untuk merepresentasikan data private kelas, numerator
dan denominator. Sediakan sebuah
konstruktor yang memampukan objek kelas ini untuk diinisialisasi ketika
dideklarasikan. Konstruktor harus memuat nilai-nilai default jika tidak
terdapat penginisialisasi disediakan dan harus menyimpan pecahan dalam format
tereduksi. Sebagai contoh, pecahan 2/4 harus disimpan di dalam objek sebagai 1
di dalam numerator dan 2 di dalam denominator. Sediakan beberapa fungsi
anggota public yang melakukan setiap
tugas berikut:
a)
Menjumlahkan dua angka Rasional. Hasil yang diperoleh disimpan
dalam format tereduksi.
b)
Mengurangkan dua angka Rasional. Hasil yang diperoleh disimpan
dalam format tereduksi.
c)
Mengalikan dua angka Rasional. Hasil yang diperoleh disimpan
dalam format tereduksi.
d)
Membagi dua angka Rasional. Hasil yang diperoleh disimpan
dalam format tereduksi.
e)
Menampilkan angka Rasional dalam format a/b, dimana a adalah numerator dan b
adalah denominator.
f)
Menampilkan angka Rasional dalam format pecahan.
3)
Modifikasilah kelas Waktu pada Gambar 2.8 – 2.9 untuk
menyertakan fungsi anggota berdetak
yang menginkremen waktu yang disimpan di dalam suatu objek Waktu sebesar satu detik. Tulis sebuah program yang menguji fungsi
anggota berdetak di dalam suatu loop
yang menampilkan waktu dalam format standard selama tiap iterasi untuk
mengilustrasikan bahwa fungsi anggota berdetak
bekerja dengan benar. Pastikan untuk menguji beberapa kasus berikut:
a)
Menginkremen ke menit
berikutnya.
b)
Menginkremen ke jam berikutnya.
c)
Menginkremen ke hari
berikutnya.
4)
Modifikasilah kelas Tanggal pada Gambar 2.17 – 2.18 untuk
melakukan pemeriksaan error pada penginisialisasi nilai-nilai untuk anggota-anggota
data bulan, hari, dan tahun. Di
samping itu, sediakan sebuah fungsi anggota hariBerikutnya
untuk menginkremen hari sebesar satu. Tulis sebuah program yang menguji fungsi hariBerikunya di dalam suatu loop yang
menampilkan tanggal selama setiap iterasi untuk mengilustrasikan bahwa hariBerikutnya bekerja dengan benar.
Pastikan untuk menguji beberapa kasus berikut:
d)
Menginkremen ke bulan
berikutnya.
e)
Menginkremen ke tahun
berikutnya.
No comments:
Post a Comment