Class


Class
Konsep kelas dalam C++ ditujukan untuk menciptakan tipe data baru. Sebuah tipe terdiri
dari kumpulan bit yang merepresentasikan nilai abstrak dari instansiasi tipe tersebut serta
kumpulan operasi terhadap tipe tersebut. Sebagai contoh int adalah sebuah tipe karena
memiliki representasi bit dan kumpulan operasi seperti “penambahan dua variabel bertipe
int”, “perkalian dua variabel bertipe int”, dsb.
Dengan cara yang sama, sebuah kelas juga menyediakan sekumpulan operasi (biasanya
public) dan sekumpulan data bit (biasanya non-public) yang menyatakan nilai abstrak objek
dari kelas tersebut.
Hubungan antara kelas dengan objek dapat dinyatakan dengan analogi berikut:

class vs. object = type vs. variable
Pendeklarasian kelas (terutama fungsi anggotanya) menentukan perilaku objek dalam
operasi penciptaan, pemanipulasian, pemusnahan objek dari kelas tersebut. Dalam pemro-
graman dengan bahasa yang berorientasi objek dapat dilihat adanya peran perancang kelas
dan pengguna kelas. Perancang kelas menentukan representasi internal objek yang berasal
kelas yang dirancangnya.
Pendeklarasian kelas dilakukan seperti pendefinisian sebuah struktur namun dengan
mengganti kata kunci struct dengan class. Kata kunci class dalam C++ dapat dipan-
dang sebagai perluasan dari kata kunci struct, hanya perbedaannya nama kelas (tag-name)
dalam C++ sekaligus merupakan tipe baru.
Contoh 3.1 Sebuah struct yang memiliki prosedur/fungsi
1 struct Stack { // nama tag “Stack” sekaligus menjadi tipe baru
2 /*******************
3 * function member *
4 *******************/
5 void Pop(int&);
6 void Push (int);
7 int isEmpty();
8 // … definisi fungsi lainnya
9
10 /***************
11 * data member *
12 ***************/
13 int topStack;
14 int *data;
15 // … definisi data lainnya
16 };
Sebuah kelas memiliki satu atau lebih member (analog dengan field pada struct). Ada
dua jenis member:
10
• Data member, yang merupakan representasi internal dari kelas
• Function member, kumpulan operasi (service/method) yang dapat diterapkan terhadap
objek, seringkali disebut juga sebagai class interface
Setiap field yang dimiliki sebuah struct dapat secara bebas diakses dari luar struktur
tersebut. Hal ini berbeda dibandingkan dengan pengaksesan terhadap anggota kelas. Hak
akses dunia luar terhadap anggota (data dan fungsi) diatur melalui tiga kata kunci private,
public, dan protected. Setiap fungsi anggota kelas selalu dapat mengakses data dan fungsi
anggota kelas tersebut (dimanapun data tersebut dideklarasikan: private, public, protected).
Sedangkan fungsi bukan anggota kelas hanya dapat mengakses anggota yang berada di bagian
public. Hak akses terhadap fungsi dan data anggota kelas dinyatakan dalam Tabel 1.
Wilayah member di deklarasikan Makna
dapat diakses oleh fungsi di luar kelas (fungsi bukan
public
anggota kelas tersebut) dengan menggunakan operator
selektor (. atau ->)
hanya dapat diakses oleh fungsi anggota kelas tersebut
private
hanya dapat diakses oleh fungsi anggota kelas tersebut
protected
dan fungsi-fungi anggota kelas turunan
Tabel 1: Pengaturan hak akses melalui public, private, dan protected.
Dalam deklarasi “kelas” Stack pada Contoh 3.1, semua anggota bersifat public, karena
hal ini sesuai dengan sifat sebuah struct. Namun jika, kata kunci “struct” diganti menjadi
“class”, maka semua anggota otomatis bersifat private.
Dalam contoh tersebut, fungsi-fungsi anggota Pop(), Push(), dsb hanya dideklarasikan
namun belum didefinisikan. Pendefinisian anggota fungsi dapat dilakukan dengan dua cara:
• Di dalam class body, otomatis menjadi inline function
• Di luar class body, nama fungsi harus didahului oleh class scope
3
Contoh 3.2 menyajikan deklarasi kelas Stack dengan menggunakan kata kunci class
3
Dalam implementasi yang sebenarnya, kelas Stack selayaknya memiliki fungsi layanan untuk mengetahui
apakah stack penuh atau tidak. Layanan ini misalnya dapat diimplementasikan sebagai fungsi dengan
prototype int isFull();
11
Contoh 3.2 Deklarasi kelas Stack beserta fungsi anggota
1 class Stack {
2 public:
3 // function member
4 void Pop(int& ); // deklarasi (prototype)
5 void Push (int); // deklarasi (prototype)
6 /*— pendefinisian di dalam class body —*/
7 int isEmpty() {
8 return topStack == 0;
9 }
10 private:
11
12 // data member
13 int topStack; /* posisi yang akan diisi berikutnya */
14 int *data;
15 }; // PERHATIKAN TITIK KOMA !!!
16
17 // pendefinisian member function Pop di luar
18 // class body
19 void Stack::Pop(int& item) {
20 if (isEmpty()) {
21 // error message
22 }
23 else {
24 topStack–;
25 item = data [topStack];
26 }
27 } // TIDAK PERLU TITIK KOMA !!!
28
29 void Stack::Push (int item) {
30 if (isFull()) {
31 // error message
32 }
33 else {
34 data [topStack] = item;
35 topStack++;
36 }
37 }
3.1 Pointer implisit this
Setiap objek dari suatu kelas memiliki sendiri salinan anggota data dari kelas tersebut. Na-
mun, hanya ada satu salinan anggota fungsi untuk objek-objek dari kelas tersebut. Dengan
12
kata lain, jika ada dua objek dari suatu kelas yang memanggil salah satu fungsi anggota
kelas tersebut maka kedua objek akan menjalankan rangkaian instruksi yang terletak pada
lokasi memori yang sama, tetapi anggota data yang diakses oleh fungsi anggota tersebut
terletak pada dua lokasi memori yang berbeda.
Untuk menangani hal di atas, setiap function member secara implisit memperoleh argu-
men (parameter aktual) tersembunyi berupa pointer ke objek (implicit this pointer). Jika
pointer this ini akan digunakan di dalam fungsi anggota Push di atas, setiap pengaksesan
terhadap data anggota (maupun fungsi anggota) kelas Stack dapat diawali dengan ‘this->’.
1 void Stack::Push (int item) {
2 // . . .
3 this->data [this->topStack] = item;
4 this->topStack++;
5 // . . .
6 }
Dalam contoh berikut di atas, perhatikanlah bahwa parameter formal item tidak dapat
dituliskan sebagai this->item karena bukan merupakan anggota kelas Stack.
Pointer this merupakan sebuah rvalue sehingga ekspresi assignment terhadap this da-
lam contoh berikut tidak diijinkan:
this = …; // ruas kanan diisi suatu ekpresi
Mengapa ada this pointer?
• Pointer implisit this untuk kelas X, dideklarasikan sebagai X* this, dan digunakan
untuk mengakses member di dalam kelas tersebut
• Pointer this dapat juga digunakan memberikan return value yang berjenis kelas ter-
sebut (misalnya fungsi operator). Hal ini dibahas lebih lanjut pada Bagian 4.
3.2 Objek dari Kelas
Pendeklarasian kelas tidak mengakibatkan alokasi memory untuk kelas tersebut. Memory
dialokasikan jika ada objek yang didefinisikan dengan tipe kelas tersebut. Dengan menggu-
nakan kelas Stack di atas, berikut ini beberapa contoh pendefinisian variabel (objek) yang
berasal dari kelas Stack di atas:
1 Stack myStack;
2 Stack OprStack [10];
3 Stack * pts = new Stack;
4 Stack ns = myStack; // definition & initialization
5
6 // inisialisasi di atas sama dengan instruksi berikut:
7 // ns.topStack = myStack.topstack
8 // ns.data = myStack.data
13
3.3 Pengaksesan public member
Anggota yang publik dapat diakses melalui objek seperti layaknya pengaksesan field pada se-
buah struct. Pengaksesan terhadap data member: jika berperan sebagai lvalue maka berarti
diacu alamatnya, dan jika berperan sebagai rvalue maka berarti diacu isinya. Pengaksesan
terhadap function member berarti pemanggilan terhadap fungsi tersebut.
1 int x;
2
3 // constructor Stack harus sudah menjamin inisialisasi stack
4 // dengan benar
5
6 myStack.Push (99);
7 OprStack[2].Pop(x);
8 pts->Push(x);
9
10 if (myStack.isEmpty()) {
11 printf (“Stack masih kosong . . . “);
12 }
3.4 Constructor, Destructor, dan Copy Constructor
Untuk tipe-tipe primitif (int, float, char, double, dsb.) kompilator mengetahui bagaimana
mengalokasikan, menginisialisasi, dan mendealokasikan kumpulan bit yang merepresentasik-
an tipe tersebut. Untuk tipe data yang lebih kompleks, proses ini mungkin harus dilakukan
sendiri oleh perancang kelas. Untuk keperluan tersebut, C++ menggunakan konsep constru-
ctor dan destructor. Untuk selanjutnya, dalam penulisan “ctor” akan digunakan untuk
menyatakan constructor dan “dtor” untuk menyatakan destructor.
Constructor (destructor) adalah fungsi anggota (khusus) yang secara otomatis dipanggil
pada saat penciptaan (pemusnahan) objek. Dalam sebuah kelas, ctor dan dtor adalah fungsi
yang memiliki nama yang sama dengan nama kelas. Sebuah kelas mungkin tidak memiliki
ctor atau memiliki lebih dari satu ctor. Tugas utama konstruktor adalah untuk meng-
inisialisasi nilai-nilai dari anggota data yang dimiliki kelas. Konstruktor dapat dibedakan
menjadi dua jenis:
1. Default constructor: konstruktor yang menginisialisasi objek dengan nilai(-nilai) de-
fault yang ditentukan oleh perancang kelas. Dalam deklarasi kelas, ctor ini tidak
memiliki parameter formal.
2. User-defined constructor: konstruktor yang menginisialisasi objek dengan nilai(-nilai)
yang diberikan oleh pemakai kelas pada saat objek diciptakannya. Dalam deklarasi
kelas, ctor ini memiliki satu atau lebih parameter formal.
Destructor adalah fungsi yang namanya sama dengan nama kelas dan didahului tanda
‘~’ (tilde). Sebuah kelas dapat memiliki paling banyak satu destructor
14
Sebuah objek dapat pula diciptakan dengan cara menginisialisasinya dengan objek lain
yang sudah ada. Dalam hal ini, objek tersebut akan diciptakan melalui copy constructor.
Untuk selanjutnya “cctor” akan digunakan untuk menyatakan copy constructor.
Stack ns = myStack; // create & init
Dengan cara di atas, inisialisasi objek dilakukan oleh ”default cctor” yang melakukan
bitwise copy. Hal ini dapat mengakibatkan kesalahan untuk kelas yang memiliki
anggota data berupa pointer. Dengan contoh kelas Stack yang diberikan pada Con-
toh 3.2, anggota data dari objek ns dan myStack akan mengacu ke lokasi memori yang
sama, padahal kedua objek tersebut seharusnya tidak memiliki lokasi memori yang sama.
Jika “default cctor” tidak dikehendaki, perancang kelas harus mendefinisikan sebuah copy
constructor.
Dalam penulisan kode sebuah kelas akan terdapat dua bagian berikut:
1. Interface / specification yang merupakan deklarasi kelas, dan
2. Implementation / body yang berisi definisi dari fungsi-fungsi anggota dari kelas ter-
sebut.
Agar kelas dapat digunakan oleh pengguna, hanya bagian deklarasi kelas yang perlu
disertakan di dalam program pengguna. Untuk itu, deklarasi kelas dituliskan ke dalam file
X.h (X adalah nama kelas). Untuk mencegah penyertaan header lebih dari satu kali, deklarasi
kelas dituliskan di antara #ifdef XXXX H dan #endif (atau #endif XXXX H). Perhatikan
Contoh 3.3.
PERHATIAN: Di dalam header file, JANGAN menuliskan DEFINISI ob-
jek/variabel karena akan mengakibatkan kesalahan “multiply defined name” pada
saat linking dilakukan.
Implementasi (definisi fungsi-fungsi anggota) seperti yang terlihat pada Contoh 3.4 ditu-
liskan ke dalam file X.cc, X.cpp, X.cxx atau file X.C.
Dalam contoh pada Contoh 3.4, cctor tidak didefinisikan sehingga jika dilakukan pen-
ciptaan objek lewat inisialisasi, data member data dari dua objek yang berbeda akan me-
nunjuk ke lokasi yang sama. Selain itu, contoh kelas tersebut juga mendefinisikan dua kon-
struktor: satu default constructor (Stack::Stack()) dan satu konstruktor yang memung-
kinkan pemakai kelas Stack menyatakan ukuran maksimum stack yang akan digunakannya
(Stack::Stack (int)).
Perhatikanlah pula bahwa ctor, dtor, maupun cctor merupakan fungsi yang tidak memi-
liki tipe kembalian (return type) karena fungsi-fungsi tersebut tidak dapat dipanggil secara
eksplisit oleh pengguna, melainkan secara implisit oleh kompilator. Penjelasan lebih jauh
mengenai hal ini dapat dilihat pada bagian 3.6.
15
Contoh 3.3 Deklarasi kelas Stack
1 /*—————————————*
2 * Nama file: Stack.h *
3 * Deskripsi: interface dari kelas Stack *
4 *—————————————*/
5 #ifndef STACK_H
6 #define STACK_H
7 class Stack {
8 public:
9 // ctor — dtor
10 Stack(); // constructor
11 Stack (int); // constructor dengan ukuran stack
12 ~Stack(); // destructor
13
14 // fungsi-fungsi layanan
15 void Pop(int&);
16 void Push (int);
17 int isEmpty()
18 { // pendefinisian di dalam class body
19 return topStack == 0;
20 }
21 private:
22 // data member
23 const int defaultStackSize = 500; // ANSI: tidak boleh inisialisasi
24 int topStack;
25 int size;
26 int *data;
27 };
28 #endif STACK_H
16
Contoh 3.4 Implementasi / Body dari kelas Stack
1 /*————————————————-*
2 * Nama file: Stack.cc *
3 * Deskripsi: definisi function members dari kelas *
4 * Stack (implementation) *
5 *————————————————-*/
6 #include
7
8 // Stack constructor
9 Stack::Stack () {
10 data = new int [defaultStackSize];
11 topStack = 0;
12 size = defaultStackSize;
13 }
14
15 // constructor dengan ukuran stack
16 Stack::Stack (int s) { /* parameter s = ukuran stack */
17 data = new int [s]; /* alokasi array integer dengan
18 * index 0 .. s-1 */
19 topStack = 0;
20 size = s;
21 }
22
23 Stack::~Stack () { // destructor
24 delete [] data; // dealokasi array integer
25 size = 0;
26 data = 0;
27 }
28
29 void Stack::Pop(int& item) {
30 if isEmpty()
31 // error message
32 else {
33 topStack–;
34 item = data [topStack];
35 }
36 }
37
38 void Stack::Push (int item) {
39 // . . .
40 data [topStack] = item;
41 topStack++;
42 // . . .
43 }
17
Contoh 3.5 Program yang menggunakan Stack
1 /*—————————*
2 * Nama file: main.cc *
3 * Deskripsi: Uji coba stack *
4 *—————————*/
5 #include
6 #include … // header file lain yang diperlukan
7
8 main ()
9 {
10 // kamus
11 Stack s1; // constructor Stack()
12 Stack s2 (20); // constructor Stack (int)
13
14 // algoritma …
15 // kode program dituliskan di sini
16 }
3.5 Penciptaan/Pemusnahan Objek
Setelah Stack.h didefinisikan dan Stack.cc dikompilasi menjadi Stack.o maka pengguna
kelas dapat menuliskan program berikut yang kemudian dilink dengan Stack.o (atau melalui
pustaka tertentu). Contoh program yang menggunakan kelas Stack di atas ditunjukkan pada
Contoh 3.5.
Ada beberapa jenis objek yang dapat digunakan di dalam program C++:
• Automatic object: diciptakan jika ada deklarasi objek di dalam blok eksekusi dan
dimusnahkan (secara otomatis oleh kompilator) pada saat blok yang mengandung de-
klarasi tersebut selesai eksekusi
• Static object: diciptakan satu kali pada saat program dimulai dan dimusnahkan (secara
otomatis oleh kompilator) pada saat program selesai
• Free store object: diciptakan dengan operator new dan dimusnahkan dengan operator
delete. Kedua hal ini harus secara eksplisit dilakukan oleh pengguna kelas/objek.
• Member object: sebagai anggota dari kelas lain penciptaannya dilakukan melalui mem-
berwise initialization list. Bagian 3.7 membahas hal ini.
Contoh 3.6 menunjukkan sebuah penggalan program yang berisi tiga dari empat jenis
objek di atas.
3.5.1 Array of Objects
Untuk memberikan kemungkinan pada pemakai kelas mendeklarasikan array dari objek,
kelas tersebut harus memiliki constructor yang dapat dipanggil tanpa argumen (default con-
18
structor).
Jika array diciptakan melalui operator new, destructor harus dipanggil (melalui delete)
untuk setiap elemen array yang dialokasikan.
1 #include
2
3 Process *pa1, *pa2;
4
5 pa1 = new Process [3];
6 pa2 = new Process [5];
7
8 // … kode yang menggunakan pa1 & pa2
9
10 delete pa1; // not OK
11 delete [] pa2; // OK
3.6 Copy Constructor
Pada bagian 3.4 telah dijelaskan sekilas mengenai salah satu manfaat dari cctor. Pada bagian
ini akan dijelaskan lebih lanjut manfaat lain dari cctor. Perhatikan Contoh 3.7. Dengan
menggunakan deklarasi Stack.h yang sudah diberikan pada bagian tersebut, penciptaan
objek s3 melalui inisialisasi oleh s1 akan mengakibatkan terjadinya proses penyalinan bit per
bit dari objek s1 ke s3. Hal ini terjadi karena kelas Stack belum memiliki copy constructor.
Dalam kelas Stack seperti yang terlihat pada Contoh 3.3, proses penyalinan bit per bit
ini akan mengakibatkan efek yang tidak diinginkan. Nilai dari data anggota topStack dan
size dapat disalin bit per bit tanpa masalah, tetapi jika nilai data anggota data disalin
bit per bit akan terjadi adanya dua objek berjenis Stack yang mengacu ke lokasi memori
yang sama, padahal seharusnya keduanya mengacu ke lokasi memori yang berbeda. Untuk
menghindari hal ini, kelas Stack harus mendefinisikan sebuah copy constructor.
19
Contoh 3.6 Penciptaan / pemusnahan objek
1 #include
2
3 Stack s0; /* global (static) */
4
5 int reverse() {
6 static Stack tstack = …; /* local static */
7
8 // kode untuk fungsi reverse() di sini
9 }
10
11 main () {
12 Stack s1; // automatic
13 Stack s2 (20); // automatic
14 Stack *ptr;
15
16 ptr = new Stack(50); /* free store object */
17 while (…) {
18 Stack s3; // automatic
19
20 /* assignment dgn automatic object */
21 s3 = Stack (5); // ctor Stack(5) is called
22 /* dtor Stack(5) is called */
23
24 // … instruksi lain …
25 }
26 /* dtor s3 is called */
27
28 delete ptr; /* dtor *ptr is called */
29 }
30 /* dtor s2 is called */
31 /* dtor s1 is called */
32
33 /* dtor s0 is called */
20
Contoh 3.7 Peranan copy constructor
1 #include
2
3 void f1 (const Stack& _) { /* instruksi tidak dituliskan */}
4
5 void f2 (Stack _) { /* instruksi tidak dituliskan */ }
6
7 Stack f3 (int) {
8 /* instruksi tidak dituliskan */
9 return …; // return objek bertipe “Stack”
10 }
11
12 main ()
13 {
14 Stack s2 (20); // constructor Stack (int)
15
16 /* s3 diciptakan dengan inisialisasi oleh s2 */
17 Stack s3 = s2; // BITWISE COPY, jika
18 // tidak ada cctor yang didefinisikan
19 f1 (s2); // tidak ada pemanggilan cctor
20 f2 (s3); // ada pemanggilan cctor
21 s2 = f3 (-100); // ada pemanggilan cctor dan assignment
22 }
Copy constructor (cctor) dipanggil pada saat penciptaan objek yang dilakukan melalui:
• Deklarasi variabel dengan inisialisasi
• Pemberian parameter aktual ke parameter formal yang dilakukan secara “pass by va-
lue”. Dalam Contoh 3.7, parameter aktual s2 diberikan ke fungsi f1() tanpa adanya
pemanggilan copy constructor sedangkan parameter aktual s3 diberikan ke fungsi f2()
dengan adanya pemanggilan copy constructor.
• Pemberian nilai kembalian fungsi yang nilai kembaliannya bertipe kelas tersebut (bukan
pointer atau reference). Dalam Contoh 3.7 hal ini terjadi pada saat instruksi return
dijalankan, bukan pada saat nilai kembalian diassign ke variabel s2.
Copy constructor untuk kelas MyClass dideklarasikan sebagai fungsi dengan nama MyClass
dan memiliki sebuah parameter formal berjenis const reference dari kelas MyClass.
MyClass(const MyClass&);
Parameter aktual yang diberikan pada saat eksekusi adalah objek (yang akan diduplikasi)
yang digunakan untuk menginisialisasi objek yang sedang diciptakan oleh cctor.
Deklarasi kelas Stack harus ditambahkan dengan deklarasi cctor yang sesuai seperti
terlihat pada Contoh 3.8.
21
Contoh 3.8 Penambahan cctor pada kelas Stack
1 class Stack {
2 public:
3 Stack(); // constructor
4 Stack (int); // constructor dengan ukuran stack
5 Stack (const Stack&); // copy constructor
6 ~Stack(); // destructor
7 // …anggota-anggota lain tidak dituliskan…
8 };
Yang harus dituliskan dalam definisi cctor adalah kode yang membuat penciptaan objek
secara inisialisasi menjadi benar. Dalam contoh Stack di atas, yang harus dilakukan adalah
mengalokasikan tempat untuk data member data agar setiap objek yang berasal dari kelas
Stack memiliki lokasi memori terpisah untuk menyimpan datanya. Perhatikan Contoh 3.9.
Contoh 3.9 Definisi cctor untuk kelas Stack
1 Stack::Stack (const Stack& s)
2 {
3 int i;
4
5 size = s.size;
6 topStack = s.topStack;
7 data = new int [size]; // PERHATIKAN: data member “data” harus di
8 // alokasi ulang, tidak disalin dari
9 // “s.data”.
10 for (i=0; i<size; i++)
11 data[i] = s.data[i];
12 }
Untuk memahami pemanggilan ctor, cctor, dtor perhatikan bagian berikut. Misalkan pa-
da deklarasi kelas Stack di tambahkan beberapa instruksi seperti terlihat pada Contoh 3.10
yang dipanggil oleh program pada Contoh 3.11.
22
Contoh 3.10 Deklarasi ctor, cctor, dan dtor dari Stack
1 /* Nama file: Stack.h */
2 /* Deskripsi: ujicoba constructor, destructor, */
3
4 #ifndef STACK_H
5 #define STACK_H
6 class Stack {
7 public:
8 Stack() { printf (“ctor %x\n”, this); }
9 Stack (const Stack&) { printf (“cctor %x\n”, this); }
10 ~Stack() { printf (“dtor %x\n”, this); }
11 };
12 #endif STACK_H
Contoh 3.11 Program untuk observasi ctor, dtor, cctor
1 /*———————————————–*
2 * Nama file: test.cc *
3 * Deskripsi: pengamatan pemanggilan ctor, dtor, *
4 * cctor *
5 *———————————————–*/
6 #include
7
8 f (Stack _) {
9 printf (“ffffffff\n”);
10 }
11
12 Stack ll;
13
14 main() {
15 printf (“11111111\n”);
16 Stack x;
17 printf (“22222222\n”);
18 Stack y = x;
19 printf (“33333333\n”);
20 f(x);
21 printf (“44444444\n”);
22 }
Hasil eksekusi dari Contoh 3.11 ditunjukkan pada Gambar 1.
23
ctor 0x198a8
11111111
ctor 0x5f514
22222222
cctor 0x5f510
33333333
cctor 0x5f50c
ffffffff
dtor 0x5f50c
44444444
dtor 0x5f510
dtor 0x5f514
dtor 0x198a8
Gambar 1: Hasil eksekusi program pada Gambar 3.11
3.7 Constructor Initialization List
Misalkan ada sebuah kelas Parser yang memiliki data member yang bertipe Stack seperti
yang dideklarasikan di atas dan salah satu ctor dari Parser memberikan kemungkinan peng-
guna objek untuk menciptakan objek Parser dengan sekaligus menyatakan ukuran Stack
yang dapat digunakan Parser tersebut. Perhatikan Contoh 3.12.
Contoh 3.12 Kelas Parser yang memiliki data member bertipe Stack
1 #include
2
3 class Parser {
4 public:
5 Parser(int);
6 // …
7 private:
8 Stack sym_stack, op_stack;
9 // …
10 };
Pada saat constructor Parser::Parser(int) dipanggil, anggota data sym stack akan
diciptakan dan diinisialisasi melalui konstruktor default Stack::Stack(). Bagaimana jika
inisialisasi ingin dilakukan melalui user-defined constructor Stack::Stack(int)? Ada dua
cara untuk melakukan hal ini:
• Member sym stack diciptakan melalui default ctor, lalu ctor Parser::Parser() me-
lakukan operasi assignment. Dengan cara seperti ini terjadi pemanggilan konstruktor
Stack::Stack() (tanpa parameter) serta fungsi yang menangani operasi assignment
(dua kali pemanggilan).
24
• ctor Parser::Parser() melakukan inisialisasi Stack melalui member initialization list
seperti ditunjukkan pada Contoh 3.13. Dengan cara ini, hanya ada satu kali pemang-
gilan konstruktor yaitu Stack::Stack (int)
Manfaat constructor initialization list adalah performansi yang lebih baik. Oleh karena
itu, anggota data yang bertipe non-primitif sebaiknya diinisialisasi melalui cara ini.
Constructor initialization list dapat digunakan untuk menginisialisasi beberapa member
sekaligus. Untuk melakukan hal ini, nama anggota data yang diinisialisasi dituliskan sete-
lah parameter formal konstruktor dan setiap nama anggota diikuti oleh sejumlah argumen
yang sesuai dengan user defined constructor yang ada. Dalam Contoh 3.13, anggota data
sym stack dan op stack diinisialiasi dengan menggunakan satu parameter aktual karena
kelas Stack dalam contoh yang sudah disajikan memiliki user defined constructor dengan
satu parameter formal.
Contoh 3.13 Memberwise initialization
1 Parser::Parser(int x) : sym_stack (x), op_stack (x)
2 {
3 // …
4 }
3.8 Const Member
Pada deklarasi variabel, atribut const menyatakan bahwa variabel tersebut bersifat konstan
dan nilainya tidak dapat diubah oleh siapapun. Anggota data (data member) maupun
anggota fungsi (function member) dapat juga memiliki atribut const. Makna dari atribut
ini adalah:
• Anggota data yang memiliki atribut const berarti bahwa nilai anggota data tersebut
akan tetap sepanjang waktu hidup objeknya. Standard ANSI mengharuskan pengisian
nilai awal terhadap anggota data const dilakukan pada saat objek tersebut diciptakan.
Bandingkanlah dengan definisi konstan yang juga memanfaatkan pengisian nilai awal
pada saat penciptaan berikut:
const int max_size = 5000;
Untuk sebuah objek, pengisian tersebut harus dilakukan melalui constructor initiali-
zation list seperti pada Bagian 3.7.
• Anggota fungsi yang memiliki atribut const berarti bahwa fungsi tersebut tidak akan
mengubah objek yang memanggilnya.
Object yang ditandai sebagai const tidak boleh memanggil fungsi anggota yang tidak
memiliki atribut const karena hal tersebut dapat mengakibatkan perubahan status
objek tersebut.
25
Dalam contoh Stack di atas, fungsi yang dapat mendapatkan atribut const adalah
isEmpty(), sedangkan data yang dapat mendapatkan atribut const adalah size. Pada
Contoh 3.14 ditunjukkan bagaimana penulisan deklarasi fungsi dan data tersebut setelah
mendapatkan atribut const.
Contoh 3.14 Pemanfaatan const pada anggota fungsi
1 class Stack {
2 // …
3 public:
4 Stack ();
5 Stack (int s);
6 Stack (const Stack&);
7 int isEmpty() const; /* keyword ‘const’ dituliskan pada
8 * deklarasi maupun definisi
9 * member function */
10 private:
11 const int size;
12 };
13
14 int Stack::isEmpty () const { // 0) {
printf (“…..”);
}
• Anggota fungsi statik tidak memiliki pointer implisit this
• Data member yang statik diinisialisasi tanpa perlu adanya objek dari kelas tersebut
3.10 Friend
Dalam C++, sebuah kelas (A) atau fungsi (F) dapat menjadi friend dari kelas lain (B). Dalam
keadaan biasa, kelas A maupun fungsi F tidak dapat mengakses anggota (data/fungsi) non
public milik B. Dengan adanya hubungan friend ini, A dan F dapat mengakses anggota non
public dari B. Deklarasi friend dituliskan dari pihak yang memberikan ijin. Pemberian ijin
ini tidak bersifat dua arah, yang berarti dalam kode berikut, kelas B tidak memiliki hak
untuk mengaskses anggota non-public dari kelas A. Dalam contoh ini, realisasinya adalah:
1 class B { // kelas “pemberi ijin”
2 friend class A;
3 friend void F (int, char *);
4
5 private:
6 // …
7 public:
8 //…
9 };
Fungsi yang dideklarasikan dengan atribut friend merupakan fungsi di luar kelas se-
hingga objek parameter aktual mungkin dilewatkan secara call-by-value. Akibatnya operasi
yang dilakukan terhadap objek bukanlah objek semula, melainkan salinan dari objek terse-
but. Fungsi anggota merupakan fungsi di dalam kelas dan operasi yang dilakukannya selalu
berpengaruh pada objek sesungguhnya.
Kriteria penggunaan atribut friend:
• Sedapat mungkin hindari penggunaan friend. Penggunaan friend di antara kelas
menunjukkan perancangan kelas yang kurang baik. Jika kelas A menjadikan kelas B
sebagai friend maka kemungkinan besar kelas A dan B seharusnya tidak dipisahkan
• Jika operasi yang dijalankan oleh sebuah fungsi friend mengubah status dari objek,
operasi tersebut harus diimplementasikan sebagai fungsi anggota
• Gunakan friend untuk overloading pada operator tertentu. Hal ini dibahas lebih
lanjut di Bagian 4.
28
3.11 Nested Class
Dalam keadaan tertentu, perancang kelas membutuhkan pendeklarasian kelas di dalam de-
klarasi suatu kelas tertentu. Sebagai contoh pada deklarasi kelas List yang merupakan list
dari integer, kita mungkin membutuhkan deklarasi kelas ListElem untuk menyatakan ele-
men list tersebut. Operasi-operasi terhadap list didefinisikan di dalam kelas List, namun
demikian ada kemungkinan operasi-operasi ini membutuhkan pengaksesan terhadap bagi-
an non-publik dari kelas ListElem sehingga penggunaan friend dituliskan di dalam kelas
ListElem seperti yang terlihat pada Contoh 3.15.
Contoh 3.15 Kelas List dan ListElem
1 class List;
2
3 class ListElem {
4 friend class List;
5 public:
6 //
7 private:
8 };
9
10 class List {
11 public:
12 //
13 private:
14 //
15 };
Sesungguhnya, pemakai kelas List tidak perlu mengetahui keberadaan kelas ListElem.
Yang perlu ia ketahui adalah adanya layanan untuk menyimpan nilai (integer) ke dalam list
tersebut maupun untuk mengambil nilai dari list tersebut.
Dalam keadaan di atas, kelas ListElem dapat dijadikan sebagai nested class di dalam
kelas List dan deklarasinya dapat dituliskan seperti pada Contoh 3.16.
Contoh 3.16 Deklarasi ListElem di dalam List
1 class List {
2 //
3 //
4 class ListElem {
5 //
6 //
7 };
8 };
Namun demikian, ada pertanyaan yang mungkin muncul: “Dimanakah kelas ListElem
29
dideklarasikan? Di bagian publik atau non-publik?”. Jika ditempatkan pada bagian public
dari kelas List, maka bagian publik dari kelas ListElem akan tampak ke luar kelas List se-
bagai anggota yang juga publik. Sebaliknya, jika ditempatkan pada bagian non-publik, maka
bagian publik dari kelas ListElem akan tersembunyi terhadap pihak luar kelas List, namun
akan tetap terlihat oleh anggota-anggota kelas List. Efek terakhir inilah yang diinginkan,
sehingga dengan demikian deklarasi kelas ListElem ditempatkan di bagian non-publik se-
perti yang ditunjukkan pada Contoh 3.17. Dalam keadaan ini juga kemungkinan besar kelas
ListElem tidak perlu memiliki bagian non-publik.
Contoh 3.17 Deklarasi ListElem di dalam List
1 class List {
2 public:
3 // bagian public kelas List
4 // …
5 private:
6 class ListElem {
7 public:
8 // semua anggota ListElem berada pada bagian publik
9 };
10
11 // definisi anggota private kelas List
12 };
3.11.1 Fungsi Anggota Nested Class
Dalam contoh List dan ListElem di atas, pendefinisian kelas ListElem berada di dalam
lingkup kelas List sehingga nama scope yang harus digunakan dalam mendefinisikan kelas
ListElem adalah “List::ListElem” bukan hanya sekedar “ListElem::”. Jika kelas List
merupakan kelas generik yang memiliki parameter generik Type, maka nama scope menjadi
“List::ListElem”. Perhatikan Contoh 3.18 dan Contoh 3.19.
Penggunaan nama parameter generik Type di dalam nested class ListElem pada baris
12 mengakibatkan kelas ListElem menjadi kelas generik. Perhatikanlah pula penulisan na-
ma scope pada baris 19, 24, dan 29, serta jenis kembalian fungsi “operator=” dari kelas
ListElem.
4 Operator Overloading dan Fungsi operator
Function overloading adalah fasilitas yang memungkinkan sebuah nama fungsi yang sama
dapat dipanggil dengan jenis & jumlah parameternya (function signature) yang berbeda-
beda. Sebenarnya hal ini sudah sering kita gunakan, secara tidak langsung, tanpa sadar.
Misalnya, untuk penambahan dua bilangan kita menggunakan menggunakan simbol + baik
untuk penambahan integer maupun real.
30
Contoh 3.18 Deklarasi anggota ListElem di dalam List
1 // File: List.h
2 template
3 class List {
4 public:
5 //… bagian ini tidak dituliskan …
6 private:
7 class ListElem {
8 public: // seluruh anggota bersifat publik
9 ListElem (const Type&);
10 ListElem (const ListElem&);
11 ListElem& operator (const ListElem&);
12 Type info; // <– perhatikan parameter generik
13 ListElem* next;
14 };
15 };
Contoh 3.19 Definisi fungsi anggota nested class ListElem
16 // File: List.h
17
18 template
19 List::ListElem::ListElem (const Type& v) : info (v) {
20 next = 0;
21 }
22
23 template
24 List::ListElem::ListElem (const ListElem& x) : info (x.info) {
25 next = x.next;
26 }
27
28 template
29 List::ListElem& List::ListElem::operator= (const ListElem& x) {
30 info = x.info;
31 next = x.next;
32 return *this;
33 }
31
int a, b, c;
float x, y, z;
c = a + b; /* “fungsi +” di-overload */
z = x + y;
Jika penambahan dituliskan sebagai fungsi tambah(), maka kedua operasi tersebut dapat
dituliskan sebagai:
c = tambah (a, b);
z = tambah (x, y);
dengan sebelumnya mendeklarasikan dua prototipe fungsi tambah sbb:
int tambah (int, int);
float tambah (float, float);
Fasilitas function name overloading dalam C++ dapat juga diterapkan pada simbol-
simbol operasi. Hal ini dapat dimanfaatkan oleh perancang kelas untuk menggunakan
simbol-simbol operator dalam pemanipulasian objek, seperti pada contoh berikut:
Matrix A, B, C;
C = A * B; /* perkalian matrix */
Complex x, y, z;
x = y / z; /* pembagian bilangan kompleks */
Process p;
p << SIGHUP; /* pengiriman sinyal dalam Unix */
Hal ini dapat diwujudkan oleh perancang kelas dengan menggunakan fungsi anggota yang
namanya terdiri kata kunci operator dan diikuti oleh simbol operator yang digunakan.
Fasilitas ini disebut sebagai fungsi operator (operator function). Dalam contoh-contoh di
atas, perancang kelas Matrix, Complex, dan Process harus menuliskan deklarasi kelas seperti
pada Contoh 4.1.
Dari contoh di atas terlihat dua bentuk pendeklarasian fungsi operator: (a) sebagai non-
anggota4 atau (b) sebagai fungsi anggota biasa. Dalam contoh-contoh di atas, seluruh opera-
tor merupakan operator biner (menerima dua argumen), namun terdapat perbedaan jumlah
argumen ketika diimplementasikan sebagai fungsi non-anggota atau sebagai fungsi anggota.
Jika diimplementasikan sebagai fungsi anggota, maka fungsi tersebut memiliki pointer im-
plisit this sehingga pada saat operasi dilakukan pointer this tersebut akan menunjuk ke
alamat objek pada “ruas kiri” dari operasi. Dalam contoh kelas Complex di atas, operasi
pembagian dua bilangan kompleks diwakili oleh fungsi anggota operator/ yang menerima
satu parameter. Parameter tersebut mewakili objek pada ruas kanan operasi.
Misalkan dalam contoh Stack yang sudah dibahas sejauh ini akan ditambahkan fungsi
operator untuk push, dan pop dengan menggunakan simbol operator <>. Pada kelas
Stack harus ditambahkan tiga prototipe fungsi berikut seperti terlihat pada Contoh 4.2.
4
Harus dideklarasikan sebagai friend jika mengakses anggota yang non-public
32
Contoh 4.1 Deklarasi kelas yang memanfaatkan operator
1 class Matrix {
2 public:
3 // fungsi-fungsi operator
4 friend Matrix& operator* (const Matrix&, const Matrix&);
5 // …
6 };
7
8 class Complex {
9 // …
10 public:
11 Complex& operator/ (const Complex&);
12 // …
13 };
14
15 class Process {
16 // …
17 public:
18 void operator<< (int);
19 // …
20 };
Contoh 4.2 Deklarasi kelas Stack yang memanfaatkan fungsi operator
1 class Stack {
2 //
3 public:
4 void operator<> (int&); // untuk pop
6 // …
7 };
33
Definisi dari kedua fungsi operator ini adalah sama seperti definisi dari prosedur Push()
dan Pop(). Bahkan jika juga didefinisikan, prosedur Push() dan Pop() dapat dipanggil dari
dalam kedua fungsi operator tersebut seperti tertera pada Contoh 4.3.
Contoh 4.3 Pendefinisian fungsi operator pada kelas Stack
1 void Stack::operator<>(int& item) {
6 Pop (item);
7 }
Bandingkanlah prototipe void operator<< (int) dengan void Push (int). Dari ke-
dua prototipe ini tampak bahwa pengguna kelas Stack dapat memanfaatkan fungsi dengan
nama Push dan operator<> (int&) dengan void Pop
(int&). Dengan sudut pandang ini, maka pengguna kelas Stack dapat menuliskan kode
seperti pada Contoh 4.4.
Contoh 4.4 Pemanfaatan fungsi operator
Stack s, t;
s.Push (100);
t.operator<>(500)” di atas dapat juga dituliskan se-
bagai:
t << 500;
Jika operator<> diimplementasikan sebagai non-anggota (friend)5 maka
deklarasi kelas dan definisi kedua fungsi tersebut menjadi seperti terlihat pada Contoh 4.5.
Dengan didefinisikannya kedua operator sebagai fungsi non-anggota maka pengguna da-
pat memanfaatkan operasi tersebut hanya sebagai operator <>, dan tidak sebagai
fungsi dengan nama operator<>. Pemanfaatan yang benar diberikan pada

About Sintata
Seek and Share Knowledge

3 Responses to Class

  1. andikoala says:

    panjang ny……….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: