Pendahuluan Prolan dan bahasa C.zip

Pengenalan Singkat C++

J.Linggarjati May 7, 2007

Pada saat training fullcast minggu ke 11 dan 12, topik yang tertera di silabus adalah ”Introduction to C++” dan ”OOP in C++”. Melihat kembali ke buku absensi fullcast, topik ini telah dibahas pada pertemuan ke 53 hingga pertemuan ke 60. Dilihat dari Judul dan Rincian Materi, maka berikut ini apa yang terjadi di pertemuan ke-53 hingga 60.

1. OOP and Review: Review profiling and memory leak; OOP: Encapsu- lation and Inheritance

2. Exercise Encapsulation and pointer

3. OOP-Mini Project: Review and discussion, mini project (pertemuan

55 hingga 58).

4. Polymorphysim, OOP Project 2

5. OOP Project 2, Presentation Projek yang dibuat adalah database mini; projek ini sudah dilakukan

pada minggu-minggu sebelumnya (hanya saja dalam bahasa C). Maka projek database mini tersebut dikonversi ke bahasa C++.

Tulisan kecil ini mencoba untuk menangkap beberapa hal tentang C++, hal ini mengingat peserta fullcast terdiri dari dua jurusan, Teknik Informatika dan Sistem Komputer. Berdasarkan silabus matakuliah, Sistem Komputer belum pernah mendapat mata-kuliah C++, hal ini tentu menjadi kendala, tetapi tidaklah terlalu besar, mengingat C sudah mereka kuasai dengan baik. Baiklah, tulisan ini bukan pekerjaan pribadi, tetapi dari terjemahan bahasa inggris yang berjudul ”A Quick Introduction to C++ - Tom Anderson”. Secara umum, tulisan ini sangat baik, karena si penulis asli sudah mengajar C++ di kelas maupun di projek selama 15 tahun. Jadi pengalaman dia sungguh berharga bagi mahasiswa untuk dibaca dan dimengerti.

Kemudian akan ditambahkan dengan informasi tentang projek database mini - sqlite3 dari fullcast. Semoga bermanfaat.

1 Pengenalan

Artikel ini memperkenalkan bahasa C++ secara sederhana, dari sisi konsep- tual dan point-point penting dari subset C++ yang lebih mudah dimengerti daripada mempelajari seluruh topik-topik pada C++. Tulisan ini dibuat oleh Tom Anderson, sebagai bahan mengajar di mata-kuliah Sistem Op- erasi - Projek Nachos (Not Another Completely Heuristic Operating Sys- tem). Meskipun orientasi tulisan ini pada Sistem Operasi, namun ia mem- buat contoh-contoh program yang mampu memberikan gambaran bagi pem- ula C++, tentang dasar dari bahasa C++.

Dia memberikan gambaran bahwa dasar-dasar C++ dapat dimengerti dan dicoba dalam hitungan hari. Hal mendasar yang ia tekankan adalah bahwa C++ sebagai OOP (Object Oriented Programming) adalah teknik yang berguna untuk men-sederhanakan program. Meskipun pada kenyataan- nya, C++ adalah bahasa yang kompleks dengan fitur-fitur yang sangat sulit untuk dicari manfaatnya.

Maka kemudian ia memberikan batasan apa yang perlu, agak perlu, dan tidak perlu bagi pemula C++:

1. Konsep dasar yang harus dimengerti, yaitu classes, member functions, constructors, destructors - hal-hal ini harus di ketahui dan dimengerti cara penggunaannya.

2. Hal-hal yang terkadang berguna, yaitu single inheritance dan templates - hal-hal ini harus diketahui oleh pemula C++, tapi dapat dihindari pada prakteknya, paling tidak hingga mendapatkan cukup pengalaman di C++.

3. Fitur-fitur C++ yang bukanlah ide bagus, dan justru harus dihindari, seperti multiple inheritance, exceptions, overloading, references, dan lain-lain.

Tentu saja, fitur-fitur C++ pada point terakhir memiliki fungsinya, sama seperti fungsi goto - unstructured programming, program yang menggunakan goto atau multiple inheritance dapat lebih sederhana. Namun, berdasarkan pengamatan, hampir seluruh programmer tidak akan pernah menggunakan fitur-fitur tersebut; apabila anda menggunakannya, sebagai pemula, kemu- ngkinan besar akan salah dalam penggunaannya. Tetapi jika Anda ingin menggunakan fitur seperti multiple inheritance, maka, saran saya adalah mengimplementasikan program Anda dalam 2 versi, dengan dan tanpa fi- tur tersebut; kemudian pilih mana yang lebih sederhana. Tentu, langkah ini Tentu saja, fitur-fitur C++ pada point terakhir memiliki fungsinya, sama seperti fungsi goto - unstructured programming, program yang menggunakan goto atau multiple inheritance dapat lebih sederhana. Namun, berdasarkan pengamatan, hampir seluruh programmer tidak akan pernah menggunakan fitur-fitur tersebut; apabila anda menggunakannya, sebagai pemula, kemu- ngkinan besar akan salah dalam penggunaannya. Tetapi jika Anda ingin menggunakan fitur seperti multiple inheritance, maka, saran saya adalah mengimplementasikan program Anda dalam 2 versi, dengan dan tanpa fi- tur tersebut; kemudian pilih mana yang lebih sederhana. Tentu, langkah ini

Teknik yang baik dalam mempelajari sebuah bahasa adalah membaca projek program yang jelas untuk dicerna pada bahasa tersebut. Penulis ini membuah projek Nachos sebagai contoh program yang ia harapkan dapat mudah dibaca; Nachos ditulis dalam subset C++, seperti yang akan dije- laskan pada bagian berikutnya dari tulisan ini.

2 C dalam C++

Secara garis besar, C++ adalah superset dari C, atau C adalah subset dari C++. Dan program ANSI C yang ditulis dengan standard dapat dikompilasi dengan kompiler C++. Namun ada beberapa perbedaan mendasar, sebagai berikut:

1. Seluruh fungsi harus dideklarasikan terlebih dahulu sebelum mereka

digunakan, tidak seperti pada C yang di-defaultkan ke tipe int.

2. Seluruh deklarasi fungsi dan definisi headers harus menggunakan gaya dekrasi baru, sebagai contoh:

extern int foo(int a, char* b); Sedangkan, extern int foo(); berarti fungsi foo tidak memiliki argu-

ments. Bahkan, beberapa saran mengatakan untuk menggunakan kom- piler C++, walau untuk koding C sjaja, karena ia akan menangkap error, seperti misused functions (fungsi yang salah penggunaannya).

3. Jika Anda perlu untuk me-link file objek C dengan C++, maka Anda perlu mendeklarasi fungsi C untuk C++, sebagai berikut:

extern "C" int foo(int a, char* b); Jika tidak maka kompiler C++ akan mengubah nama fungsi foo dalam

bentuk yang aneh.

4. Terdapat beberapa kata kunci baru dalam C++, yang tentunya Anda harus hindari untuk digunakan sebagai identifier - beberapa yang umum adalah new, delete, const, dan class.

3 Konsep-konsep Dasar

Sebelum memberikan contoh-contoh program C++, mari kita lihat beberapa konsep dasar bahasa OOP. Jika penjelasan awal ini terkesan sulit dicerna, maka selanjutnya akan ada beberapa contoh program untuk memperjelas.

1. Classes dan objek. Sebuah class sama dengan struc pada C, hanya saja semua definisi struktur data dan semua fungsi yang beroperasi terhadap struktur data tersebut di gabung menjadi satu kesatuan yang disebut dengan class. Objek adalah instan dari sebuah class; beberapa objek berbagi fungsi yang sama dengan objek-objek lainnya dari satu class yang sama, namun setiap objek (setiap instan) memiliki struktur data terpisah. Kesimpulan sebuah class, mendefinisikan 2 aspek dari objek: data yang dimiliki dan sifat yang dipunyai.

2. Member functions. Sifat dari suatu class, diimplementasikan dalam fungsi, yang disebut member-functions. Terkadang di buku-buku C++, hal ini disebut juga dengan method dari suatu class. Selain member functions, sifat class juga ditentukan oleh:

(a) Apa yang Anda lakukan ketika objek baru dibuat (fungsinya diberi- nama constructor) - dengan kata lain melakukan inisialisasi data objek.

(b) Apa yang Anda lakukan ketika objek dihapus (fungsinya diberi- nama destructor)

3. Private versus public members. Public member dari sebuah class adalah sesuatu yang dapat dibaca atau ditulis oleh siapa saja, berkaitan den- gan data member, atau dipanggil oleh siapa saja, berkaitan dengan member function. Sedangakan sebuah private member dapat hanya dibaca, ditulis atau dipanggil oleh sebuah member function pada class itu sendiri.

Class digunakan untuk 2 alasan utama: (1) Class membuat program lebih mudah untuk diorganisasi karena Anda dapat menggabungkan data dengan fungsi yang memanipulasi data tersebut. Dan (2) Penggunaan private members membuat program mampu melakukan information hiding, sehingga Anda dapat lebih memastikan tentang bagaimana informasi mengalir dalam program.

3.1 Classes

C++ classes pada intinya serupa dengan struct pada C. Malah, pada C++, struct dianggap sebagai class yang hanya memiliki data member public. Pada penjelasan kedepan tentang bagaimana classes bekerja, kita akan menggu- nakan sebuah stack class sebagai contoh.

1. Member functions. Berikut ini adalah sebuah contoh dari satu class dengan sebuah member function dan beberapa data members:

class Stack { public: // Push an integer, checking for overflow. void Push(int value); //Index of the top of the stack. int top; // The elemetns of the stack. int stack[10]; };

void Stack::Push(int value) {

ASSERT(top < 10); // stack should never overflow stack[top++] = value;

} Class Stack memiliki dua data members, top dan stack, dan satu mem-

ber function, Push. Notasi class::function menyatakan fungsi yang merupakan anggota dari class tersebut (aturan dalam menulis nama fungsi adalah dengan huruf besar diawal suku kata). Isi dari fungsi itu sendiri didefinisikan dibawahnya.

Perhatikan bahwa kita menggunakan fungsi ASSERT untuk menge- cek apakah stack telah penuh; ASSERT akan memberitahu debugger apabila kondisi-nya adalah false. Sangat baik untuk menggunakan AS- SERT sepanjang baris pada program yang Anda buat. Akan lebih baik jika mampu mendeteksi kesalahan program dengan memanfaatkan fungsi ASSERT, hal ini dapat menghindari hal yang lebih fatal, misal- nya program menulis data pada lokasi acak di memori.

Dalam praktek pemrograman C++, definisi class Stack akan ditulis di file stack.h, sedangkan definisi dari member-functions, seperti Stack::Push, akan ditulis di file stack.cc.

Jika kita memiliki sebuah pointer, katakan s, yang menunjuk ke sebuah objek Stack, maka kita dapat mengakses variabel top dengan cara,

s->top sama seperti di C. Namun di C++, kita juga dapat memanggil member

fungsi dengan sintaks: s->Push(17); Tentu saja, seperti di C, pointer s harus menunjuk ke objek stack yang

sesungguhnya. Didalam member function, kita dapat mengacu ke member dari class

tersebut hanya dengan nama-nya saja. Atau dengan kata lain, defin- isi class telah membuat ruang-lingkup yang menyertakan definisi dari member (yaitu fungsi dan data).

Perhatikan juga bahwa jika Anda berada di dalam sebuah member func- tion, maka Anda mendapatkan sebuah pointer yang menunjuk ke objek yang memanggil, dengan cara menggunakan variabel this. Namun, jika Anda ingin memanggil member function lain pada objek yang sama, maka Anda tidak memerlukan pointer this ini. Mari kita memperluas contoh Stack untuk mengilustrasikan hal ini, dengan menambahkan fungsi Full().

class Stack { public: // Push an integer, checking for overflow void Push(int value); bool Full(); int top; int stack[10];

} bool Stack::Full() {

return (top ==10); }

Sekarang kita dapat menulis ulang Push sebagai berikut: Sekarang kita dapat menulis ulang Push sebagai berikut:

} Atau kita dapat juga menulis bagian ASSERT, sebagai berikut:

ASSERT(!(this->Full()); tetapi ingat di dalam sebuah member function, this−> tidak perlu

ditulis (implisit). Tujuan dari member functions adalah untuk meng-enkapsulasi fung-

sionalitas dari suatu tipe objek berikut dengan data yang dimiliki oleh objek tersebut. Ingat bahwa sebuah member function tidak memakan tempat didalam sebuah objek dari suatu class.

2. Private members. Kita dapat mendeklarasikan sebagian members dari class sebagai pri-

vate, yang berarti tersembunyi dari semua, kecuali dari member function- nya sendiri; dan sebagian members-nya lagi sebagai public, yang be- rarti dapat dilihat dan diakses oleh semua. Baik data member maupun member functions dapat menjadi public atau private.

Pada contoh Stack, perhatikan bahwa karena kita telah memiliki fungsi Full(), maka kita tidak perlu melihat data top dan data stack[ ] dari luar class tersebut - bahkan, kita menginginkan bahwa users dari class Stack tidak perlu tahu bagaimana implementasi internal dilakukan, ini penting, apabila kita akan mengubah implementasi iternalnya. Dengan demikian kita menulis-ulang class Stack, sebagai berikut:

class Stack { public: // Push an integer, checking for overflow. void Push(int value); //Returns TRUE if the stack is full, FALSE otherwise. bool Full();

private: int top;

// Index of the top of the stack. int stack[10]; // The elements of the stack. };

Perhatikan, sebelumnya, dengan diberikan sebuah pointer ke objek Stack, katakan pointer s, semua bagian dari program dapat mengak- ses s−>top; dan tentunya hal ini tidak baik dari sisi pemrograman. Sekarang, dengan dibuatnya top sebagai data member private, maka hanya member fungsi Full() yang dapat mengakses top. Jika bagian lain dari keseluruhan program mencoba mengakses ke s−>top, maka kompiler C++ akan melaporkan terjadinya error.

Anda dapat menentukan bagian dari suatu class private: atau public:. Jika tidak dispesifikasikan, maka class members akan private, maka contoh class Stack dapat ditulis, sebagai berikut:

class Stack { int top; int stack[10];

public: void Push(int value); bool Full();

}; Bentuk apapun yang Anda sukai hanyalah masalah gaya pemrograman,

namun sebaiknya dibuat eksplisit, sehingga terlihat jelas apa yang di- maksud. Pada projek Nachos, kita membuat semuanya eksplisit.

Apa yang bukan hanya masalah gaya pemrograman adalah semua data member dari sebuah class sebaiknya private. Semua operasi pada data seharusnya melalui class member functions. Membuat data private, menambah sifat modularitas dari keseluruhan sistem, karena Anda dapat merevisi bagaiman data member disimpan, tanpa mengubah bagaimana Anda mengakses data tersebut.

3. Constructors dan operator new. Pada C, untuk membuat sebuah objek baru dari tipe Stack, seseorang

dapat menulisnya, sebagai berikut: struct Stack *s = (struct Stack *) malloc(sizeof (struct Stack));

InitStack(s, 17); Fungsi InitStack() dapat memiliki argument kedua sebagai ukuran dari

stack yang akan dibuat dan menggunakan malloc() untuk mendapatkan array dari 17 integers.

Cara hal tersebut dilakukan dalam C++ adalah sebagai berikut:

Stack *s = new Stack(17); Fungsi new menggantikan fungsi malloc(). Sedangkan untuk menen-

tukan bagaimana suatu objek diinitialisasi, seseorang dapat mendeklarasi sebuah fungsi constructor, sebagai member dari class tersebut, dimana nama fungsi constructor dibuat sama dengan nama classnya:

class Stack { public: Stack(int sz);

// Constructor: initialize variables, allocate space. void Push(int value); // Push an integer, checking for overflow. bool Full();

// Returns TRUE if the stack is full, FALSE otherwise. private: int size; int top; int *stack;

}; Stack::Stack(int sz) {

size = sz; top = 0; stack = new int[size]; // Let’s get an array of integers.

} Terdapat beberapa hal baru pada contoh koding tersebut, kita coba

lihat satu persatu. Operator new secara otomatis membuat (yaitu mengalokasikan) ob-

jek tersebut dan kemudian memanggil fungsi constructor untuk ob- jek yang baru dibuat ini. Hal yang sama terjadi jika, misalnya Anda mendeklarasikan sebuah objek sebagai variabel otomatis (variabel bi- asa) didalam sebuah fungsi atau blok - maka kompiler akan menga- lokasikan ruang untuk objek tersebut didalam bagian stack dan me- manggil contructor didalam objek tersebut.

Dalam contoh ini, kita membuat dua (2) buah stack dengan ukuran yang berbeda-beda; satu mendeklarasikan objek sebagai suatu variabel otomatis, dan satunya lagi dengan perintah new (variabel pointer).

void test() { Stack s1(17); Stack *s2 = new Stack(23);

Perhatikan, terdapat dua cara untuk menyediakan argument bagi con- structors: pertama dengan new, Anda menaruh daftar argument sete- lah nama class, dan kedua dengan variabel automatis (biasa atau global variabel), Anda menaruhnya setelah nama variabel.

Sangat penting untuk selalu mendefinisikan constructor pada setiap class yang dibuat, dan juga penting untuk memastikan bahwa con- structor menginisialisasi seitap data member dari suatu class. Jika Anda tidak mendefinisikan constructor, maka kompiler akan secara au- tomatis mendefinisikan satu constructor untuk Anda, dan percayalah, constructor tersebut tidak akan melakukan apa yang Anda harapkan. Data members akan diinitialisasi secara random, nilai yang berbeda- beda, dan pada saat program Anda berjalan sekarang, mungkin akan tidak berjalan pada lain waktu Anda mengkompilasi ulang.

Sama dengan variabel C biasa, variabel-variabel yang dideklarasikan didalam sebuah fungsi akan didealokasikan secara otomatis pada saat fungsi tersebut selesai; sebagai contoh, objek s1 dialokasi ketika fungsi test selesai. Data yang teralokasi dengan new (seperti pada objek s2) akan tersimpan pada heap, dan akan tetap berada disana walaupun fungsi telah selesai; data pada heap harus dibuang secara eksplisit den- gan menggunakan perintah delete.

Operator new dapat pula digunakan untuk mengalokasikan arrays, ter- ilustrasi berikut ini untuk array of ints dimensi size:

stack = new int[size]; Perhatikan bahwa Anda dapat menggunakan new dan delete (akan di-

jelaskan pada bagian berikutnya) dengan tipe-tipe build-in, seperti int dan char, serta dengan objek-objek class seperti Stack.

4. Destructors dan operator delete. Sama halnya dengan new sepagai pengganti malloc(), maka pengganti

free() adalah delete. Untuk mengahup objek Stack yang kita alokasikan dengan new, kita dapat melakukan:

delete s2; Hal ini akan mendealokasikan objek s2, tapi sebelumnya program akan

memanggil destructor untuk class Stack, jika terdapat destructor. De- structor ini adalah member function dari Stack yang disebut Stack(): memanggil destructor untuk class Stack, jika terdapat destructor. De- structor ini adalah member function dari Stack yang disebut Stack():

private: int size; int top; int *stack;

}; Stack::~Stack() {

delete [] stack; }

Destructor memiliki tugas untuk mendealokasikan data yang telah ter- alokasi oleh contructor. Banyak class yang tidak memerlukan destruc- tor, dan sebagian pemrogram akan menggunakan destructor untuk menutup files.

Destructor untuk sebuah objek akan dipanggil pada saat objet terse- but didealokasikan. Jika objek tersebut dibuat dengan new, maka Anda harus menggunakan delete pada objek tersebut, jika tidak maka objek tersebut akan tetap memakan tempat di memori hingga program be- rakhir - hal ini disebut ”memory leak.” Memory leak adalah hal yang buruk - meskipun virtual memory diharapkan untuk tak terbatas, Anda dapat mengalami kehabisan virtual memory - sehingga anda seharus- nya lebih berhati-hati untuk selalu menggunakan delete pada apa yang Anda telah alokasikan. Namun, menggunakan delete terlalu dini akan jauh lebih tidak baik - karena delete akan memanggil destructor dan mengalokasikan tempat pada heap untuk penggunaan kembali. Jika Anda masih menggunakan objek tersebut, maka Anda akan mendap- atkan hasil random dan tidak berulang, yang akan membuat debug- gingh menjadi sulit. Berdasarkan pengalaman, penggunaan data yang telah di-delete adalah masalah terbesar dari sulit-nya mencari kesala- han pada program. Jadi berhati-hatilah dalam penggunaan delete.

Jika objek adalah automatik, teralokasi pada eksekusi stack dari sebuah fungsi, maka destructor akan dipanggil dan ruang penggunaan mem- ori akan didealokasikan pada saat fungsi tersebut selesai; pada contoh fungsi test() diatas, s1 akan di-dealokasikan ketika fungsi test() selesai, Jika objek adalah automatik, teralokasi pada eksekusi stack dari sebuah fungsi, maka destructor akan dipanggil dan ruang penggunaan mem- ori akan didealokasikan pada saat fungsi tersebut selesai; pada contoh fungsi test() diatas, s1 akan di-dealokasikan ketika fungsi test() selesai,

Pada projek Nachos, kita selalu menggunakan teknik eksplisit untuk men- galokasikan dan meng-dealokasikan objek dengan new dan delete, agar jelas waktu constructor dan destructor dipanggil. Sebagai contoh, jika sebuah ob- jek berisi objek lainnya sebagai member variable, maka kita menggunakan new untuk secara eksplisit mengalokasikan dan menginialisasi member vari- abel, daripada secara implisit mengalokasikannya sebagai bagian dari ob- jek tersebut. C++ memiliki aturan yang kurang jelas untuk urutan dalam constructor - destructor dipanggil, pada saat Anda secara implisit menga- lokasikan dan mendealokasikan objek-objek. Pada prakteknya, meskipun sederhana, alokasi secara eksplisit membuat program lebih lambaat dan mem- buat Anda dapat lupa untuk men-dealokasikan sebuah objek (hal yang se- harusnya dihindari). Sehingga beberapa programmer tidak setuju dengan cara ini.

Ketika Anda men-dealokasikan sebuah array, Anda harus memeberiatahu kompiler bahwa Anda sedang men-dealokasikan sebuah array, sebagai perbe- daan yang jelas untuk satu element saja pada suatu array. Maka untuk menghapus suatu array integer dalam Stack::∼Stack:

delete [] stack;

3.2 Fitur-fitur dasar lain dari C++

Berikut ini beberapa fitur-fitur dasar C++ yang berguna untuk diketahui:

1. Ketika Anda mendefinisikan class Stack, maka nama Stack menjadi berguna sebagai tipe data, sama seperti pada saat menggunakan type- def dan enums.

2. Anda dapat mendefinisikan fungsi-fungsi didalam sebuah definisi class, dimana mereka menjadi inline functions, yaitu fungsi yang akan dima- sukan kedalam class itu sendiri, ketika mereka digunakan. Pedomannya adalah gunakan inline functions untuk fungsi yang berisi satu baris dan gunakan sejarang mungkin.

Sebagai contoh, kita dapat membuat fungsi Full() sebagai inline func- tion:

class Stack { ...

boot Full() { return (top == size); }; ...

}; Terdapat dua motivasi untuk inline functions: kemudahan dan per-

forma program. Jika digunakan terlalu banyak, inline functions dapat membuah koding kita menjadi membingungkan, karena implementasi dari sebuah objek tidak lagi hanya di satu tempat, tapi terpecah dua di file .h dan .c. Inlines functions terkadang dapat mempercepat kod- ing program kita (dengan meniadakan prosedur jump), namun untuk mahasiswa biasanya bukanlah sebagai faktor utama (yang lebih utama adalah membuat program yang sederhana dan tidak ada bug/error). Inline functions dapat juga menyebabkan program lebih lambat, hal ini dapat terjadi karena kode objek dari fungsi tersebut diduplikasi setiap fungsi inline dipanggil, menyebabkan cache banyak terpakai.

3. Didalam fungsi, Anda dapat mendeklarasikan beberapa variabel, mengek-

sekusi beberapa perintah, dan kemudian mendeklarasikan lagi beber- apa variabel. Hal ini dapat membuat koding lebih mudah dibaca. Se- bagai contoh, Anda dapat menulis hal seperti berikut ini:

for (int i = 0; i < 10; i++); Tergantung pada kompiler Anda, variabel i dapat tetap aktif diluar for,

namun terkadang, hal tersebut tidaklah diinginkan.

4. Komentar dapat dimulai dengan / / untuk per baris. Terkadang lebih mudah dari pada /* */ pada C.

5. C++ menyediakan beberapa fitur baru untuk penggunaan const dari

ANSI C. Ide dasar dari const adalah memberitahu kompiler bagaimana sebuah variabel atau fungsi digunakan, sehingga kompiler dapat mem- beritahu user jika ada kesalah-gunaan pada variabel maupun fungsi yang bersangkutan. Dengan cara ini, anda dapat menemukan bugs lebih cepat. Lagipula, mana yang lebih cepat? Memperbaiki sebuah error dari kompiler-flagged, atau mencari kesalahan yang sama dengan gdb?

Sebagai contoh, Anda dapat mendeklarasikan bahwa sebuah member function hanya boleh membaca member data dan tidak boleh men- gubahnya: Sebagai contoh, Anda dapat mendeklarasikan bahwa sebuah member function hanya boleh membaca member data dan tidak boleh men- gubahnya:

// Full() never modifies member data ... };

Sama seperti di C, Anda dapat pula menggunakan cosnt untuk mendeklarasikan bahwa sebuah variabel tidak boleh dimodifikasi:

const int InitialHashTableSize = 8; Hal ini lebih baik daripada menggunakan define untuk konstanta, karena

const termasuk type-checked.

6. Input atau output di C++ dapat menggunakan operator >>, <<, dan objek cin, cout. Sebagai contoh, untuk menulis ke stdout:

cout << "Hello world! This is section " << 3 << "!"; Hal ini sama dengan koding C:

fprintf(stdout, "Hello world! This is section %d!\n", 3); bedanya, pada C++, contoh koding bersifat type-safe; sedangkan den-

gan printf, kompiler tidak akan mengecek apabila Anda mencoba menc- etak angka pecahan sebagai integer. Bahkan, Anda dapat menggu- nakan printf didalam C++, tetapi Anda akan mendapatkan hasil yang aneh jika Anda menggunakan kedua-duanya, printf dan << pada stream yang sama. Pembacaan dari stdin sama dengan menulis ke stdout, bedanya stdin menggunakan operator >> sedangkan stdout menggu- nakan operator <<. Untuk membaca 2 integer dari stdin:

int field1, field2; cin << field1 << field2; // equivalent to fscanf(stdin, "%d %d", &field1, &field2); // note that field1 and field2 are implicitly modified

Cin dan cout sebenarnya diimplementasikan sebagai objek C++, meng- gunakan operator overloading dan reference parameters, namun un- tungnya Anda tidak perlu mengerti fitur-fitur tersebut untuk dapat melakukan I/O pada C++.

4 Fitur-fitur baru pada C++: Berbahaya na- mun berguna

Terdapat fitur-fitur baru pada C++, seperti single inheritance dan templates, yang mudah disalah gunakan, namun dapat secara dramatis mempermudah implementasi program jika digunakan dengan baik. Saya akan menjelaskan ide dasar dari fitur-fitur ini, berguna apabila Anda menemukannya dalam program. Anda dapat melewatkan bacaan pada bagian ini - karena bagian ini cukup panjang, kompleks, dan Anda dapat mengerti 99% koding di Nachos tanpa membaca bagian ini.

Hingga detik ini, belum ada perbedaan nyata antara C dan C++. Pada kenyatannya, programer C berpengalaman mengorganisasi fungsi- fungsi mereka dalam modul-modul yang saling terkait kedalam satu struktur data (class). Dan sering menggunakan konvensi penamaan yang mirip dengan C++, seba- gai contoh, penamaan rutin StackFull() dan StackPush(). Namun, fitur yang akan saya diskripsikan memang memerlukan pergeseran paradigma - tidak ada translasi sederhana antara program C dengan program C++. Keuntun- gan yang akan didapat, pada beberapa kondisi, Anda akan dapat menulis koding yang generik, artinya dapat digunakan untuk beberapa macam tipe objek.

Namun, saya menyarankan pemula C++ untuk tidak terlebih dahulu menggunakan fitur-fitur ini, karena bisa salah penggunaannya. Sangat mungkin menulist koding lengkap yang tidak baik dengan inheritance dan templates. Meskipun Anda mungkin berfikir hal tersebut menarik untuk ditulis seba- gai koding, namun pembaca program dapat sulit mengerti koding Anda. Saya yakin pembaca program Anda akan kesulitan dalam membaca program Anda, dan dapat berdampak pada nilai yang diberikan (hal ini untuk ma- hasiswa/i - akademisi). Sedangkan di industri, koding yang sederhana dan mudah dibaca merupakan prioritas utama. Hal yang mudah untuk menulis koding baru, tetapi biaya sesungguhnya data pada saat Anda memastikan bahwa program tersebut tetap berjalan, bahkan pada saat Anda menam- bahkan fitur baru ke program Anda.

Nachos berisi beberapa contoh dari penggunaan inheritance dan tem- plates yang baik, namun Nachos tidak menggunakannya disemua bagian program. Bahkan, jika Anda kesulitan mengerti bagian bacaan ini, jangan kuatir, Anda tidak perlu menggunakan fitur-fitur ini agar dapat menger- jakan tugas-tugas Nachos. Saya menghilangkan banyak detail fitur-fitur di C++; jadi jika Anda membutuhkan penggunaan yang lebih detail tentang inheritance dan templates, Anda dapat berkonsultasi dengan buku C++. Bacaan ini dimaksudkan hanya untuk membuat Anda dapat memulai, dan Nachos berisi beberapa contoh dari penggunaan inheritance dan tem- plates yang baik, namun Nachos tidak menggunakannya disemua bagian program. Bahkan, jika Anda kesulitan mengerti bagian bacaan ini, jangan kuatir, Anda tidak perlu menggunakan fitur-fitur ini agar dapat menger- jakan tugas-tugas Nachos. Saya menghilangkan banyak detail fitur-fitur di C++; jadi jika Anda membutuhkan penggunaan yang lebih detail tentang inheritance dan templates, Anda dapat berkonsultasi dengan buku C++. Bacaan ini dimaksudkan hanya untuk membuat Anda dapat memulai, dan

4.1 Inheritance

Inheritance menangkap kebutuhan bahwa beberapa class dari objek saling berkaitan satu dengan lainnya dalam hal yang berguna. Sebagai contoh, lists dan sorted list memiliki beberapa kesamaan fungsi - mereka sama-sama memperbolehkan user untuk melakukan insert, delete, dan find element yang berada pada list tersebut. Terdapat dua keuntungan dalam penggunaan inheritance:

1. Anda dapat menulis koding generik, yang tidak lagi mementingkan tipe objek apa yang sedang dimanipulasi. Sebagai contoh, Inheritance dipakai secara luas pada sistem window. Semua yang ada di layar (windows, scroll bars, titles, icons) adalah objek yang berdiri sendiri, tetapi mereka semua menggunakan bersama-sama beberapa member functions, seperti rutin Repaint untuk menggambar ulang objek pada layar. Dengan cara ini, koding untuk menggambar ulang seluruh layar dapat secara sederhana memanggil fungsi Repaint pada setiap objek di layar. Koding yang memanggil Repaint tidak perlu untuk menge- tahui tipe objek apa yang berada di layar, sepanjang fungsi tersebut mengimplementasikan kegiatan atau fungsi Repaint.

2. Anda dapat berbagi sebuah implementasi untuk 2 objek. Sebagai con- toh, jika Anda mengimplementasikan lists dan sorted list di C, Anda akan menulis koding tersebut didua tempat yang berbeda - bahkan mungkin, Anda akan menginginkan hanya mengimplementasikan list class. Di C++, Anda dapat mengimplementasikan sorted lists den- gan cara mengganti implementasi insert member function - sedangkan member functions lainnya sama, yaitu delete, isFull, dan print.

4.1.1 Sifat Berbagi - Shared Perbolehkan saya menggunakan Stack sebagai contoh untuk mengilustrasikan

inheritance. Implementasi Stack kita diatas, dapat ditulis ulang dengan linked lists, daripada dengan sebuah array. Koding apapun yang menggu- nakan Stack tidak akan peduli dengan implementasi apa yang digunakan, kecuali bahwa linked list tersebut tidaklah mengalami overflow. (Bahkan, kita juga dapat mengubah implementasi array untuk mampu menangani overflow, dengan secara otomatis mengatur ulang besarnya array sewaktu element dimasukkan kedalam stack).

Untuk memungkinkan kedua implementasi tetap ada, kita pertama-tama mendefinisikan sebuah abstrak Stack, berisi hanya public member functions, tetapi tanpa data.

class Stack { public: Stack(); virtual ~Stack(); virtual void Push(int value) = 0’ virtual bool Full() = 0;

}; // For g++, need these even though no data to initialize,

Stack::Stack {} Stack::~Stack() {}

Definisi Stack ini disebut base class atau terkadang superclass. Kita dapat kemudian mendefinisikan 2 class turunan (derived class) yang berbeda, atau bisa juga disebut subclasses, yang mewarisi sifat dari base class. (tentu saja, inheritance bersifat rekursif - satu derived class dapat menjadi base class dari derived class lainnya, dan seterusnya). Perhatikan bahwa saya telah menam- bahkan fungsi pada base class dengan katakunci virtual, untuk menyatakan bahwa mereka dapat didefinisikan ulang oleh setiap class turunannya. Fungsi virtual dinisialisasi dengan 0, menyatakan ke kompiler bahwa fungsi-fungsi tersebut harus didefinisikan oleh derived classes.

Berikut ini cara bagaimana kita dapat mendeklarasikan implementasi basis-array dan basis-list dari Stack. Sintaks : public Stack menandakan bahwa ArrayStack dan ListStack kedua-duanya adalah semacam Stacks, dan berabgi sifat yang sama dengan base class.

Class ArrayStack : public Stack { public: ArrayStack(int sz); ~ArrayStack(); void Push(int value); bool Full();

private: int size; int top; int *stack;

private: List *list; };

ListStack::ListStack() { list = new List; }

ListStack::~ListStack() { delete list; }

void ListStack::Push(int value) { list->Prepend(value); }

bool ListStack::Full() { return FALSE; }

Konsep yang menarik dari ini adalah saya dapat membuat pointers ke instan dari ListStack atau ArrayStack untuk sebuah variabel dari tipe Stack, dan kemudian menggunakannya seperti mereke adalah tipe data dasar.

Stack *s1 = new ListStack; Stack *s2 = new ArrayStack(17);

if (!stack->Full()) s1->Push(5); if (!s2->Full()) s2->Push(6);

delete s1; delete s2;

Kompiler akan secara otomatis memanggil operasi ListStack untuk s1, dan operasi ArrayStack untuk s2; hal ini dimungkinkan karena adanya tabel prosedur dari setiap objek; sebenarnya tabel ini semacam mekanisme switch- ing yang dapat memilih implementasi mana yang cocok, dimana objek tu- runan menimpa daftar pointer didalam tabel prosedur yang terdefinisi oleh base class. Mengacu ke koding diatas, program memanggil operasi Full, Push dan delete secara tidak-langsung melalui tabel prosedur, jadi koding program tersebut tidak perlu mengetahui tipe objek-nya masing-masing.

Pada contoh ini, karena saya tidak membuat instan dari abstract class Stack, saya tidak perlu mengimplementasikan fungsi-fungsinya. Hal ini terke- san sedikit aneh, tetapi ingat bahwa derived classes adalah implementasi dari Stack yang spesifik, dan Stack hanya berfungsi untuk mewakili sifat yang sama diantara implementasi yang berbeda. Sebagai jurusan Sistem Kom- puter, lebih mudah jika membayangkan abstract class Stack seperti multi- plexer, satu input banyak output, dimana switching diatur melalui tipe objek masing-masing.

Juga perhatikan bahwa destructor pada Stack adalah virtual function, namun constructor tidak. Hal ini jelas, ketika saya membuat sebuah objek, saya harus tahu tipe objek yang dibuat, apakah tipe ArrayStack atau List- Stack. Kompiler akan memastikan bahwa tidak ada yang membuat instan dari abstract Stack secara tidak sengaja - Anda tidak dapat menginstan-kan class yang memiliki virtual class tanpa implementasi (pure virtual, atau den- gan kata lain, jika salah satu fungsi diset nol didalam definisi class tersebut).

Namum, pada saat saya mendealokasikan sebuah objek, saya tidak perlu tahu tipe objek-nya. Pada koding diatas, saya ingin memanggil destruc- tor milik derived objek, meskipun koding program hanya tahu bahwa saya sedang menhapus sebuah objek dari class Stack. Jika destructor tersebut tidak virtual, maka kompiler akan memanggil destructor milik Stack, sedan- gkan hal ini bukanlah yang saya inginkan. Hal ini pula yang merupakan kesalahan program yang mudah dibuat (terjadi pada versi pertama tulisan ini!) - jika Anda tidak mendefinisikan sebuah destructor untuk abstaract class, maka kompiler akan mendefinisikannya satu untuk Anda secara im- plisit (dan itu bukan virtual). Hasil koding diatas tanpa virtual, akan terjadi sebuah memory leak, dan sulit untuk mendeteksi kesalahan seperti ini!

4.1.2 Implementasi Berbagi Bagaimana tentang isu koding program yang dapat digunakan kembali, salah-

satu hal penggunaan inheritance? Dalam C++, hal ini dimungkinkan dengan penggunaan member function dari sebuah baseclass pada derived class-nya. Anda juga dapat berbagi data anatr base class dengan derived classes, namun satu hal penggunaan inheritance? Dalam C++, hal ini dimungkinkan dengan penggunaan member function dari sebuah baseclass pada derived class-nya. Anda juga dapat berbagi data anatr base class dengan derived classes, namun

class Stack { public: virtual ~Stack(); // deallocate data // Push an integer, checking for overflow. virtual void Push(int value); virtual bool Full() = 0; int NumPushed();

protected: Stack(); // initialize data private: int numPushed; };

Stack::Stack() { int numPushed = 0; }

void Stack::Push(int value) { numPushed++; }

int Stack::NumPushed() { return numPushed; }

Kita dapat memodifikasi baik ArrayStack dan ListStack untuk meman- faatkan sifat baru dari Stack. Saya hanya akan memperlihatkan salah satu dari mereka:

class ArrayStack : public stack { public:

ArrayStack(int sz); ~ArrayStack(); void Push(int value); bool Full();

private: int size; int *stack;

}; ArrayStack::ArrayStack(int sz) : Stack() {

size = sz; stack = new int[size];

} void ArrayStack::Push(int value) {

ASSERT(!FULL()); stack[NumPushed()] = value; Stack::Push();

} Ada beberapa hal yang perlu diperhatikan:

1. Constructor pada ArrayStack perlu memanggil constructor untuk Stack, agar numPushed dapat terinisialisasi. Hal ini dapat dilakukan dengan cara menambahkan : Stack() pada baris pertama di dalam constructor:

ArrayStack::ArrayStack(int sz) : Stack() Hal yang sama berlaku untuk destructors. Terdapat beberapa atu-

ran khusus yang menentukan urutan pemanggilan antara construc- tor/destructor untuk base class atau constructor/destructor untuk de- rived class. Namun, bergantung pada aturan adalah hal yang tidak baik, dalam hal ini - ketergantung pada dokumentasi untuk menge- tahui apakah koding program bekerja atau tidak!

2. Saya memperkenalkan sebuah katakunci baru, protected, didalam defin- isi Stack. Bagi base class, protected menyatakan bahwa data mem- ber dan member function dapat diakses oleh derived classes (secara rekursis) dari class ini, namun tidak dapat diakses dari class lainnya. Atau dengan kata lain, data protected bersifat public ke derived classes, dan bersifat private bagi lainnya. Sebagai contoh, kita perlu Stack’s contructor untuk dipanggil oleh ArrayStack dan ListStack, tetapi kita 2. Saya memperkenalkan sebuah katakunci baru, protected, didalam defin- isi Stack. Bagi base class, protected menyatakan bahwa data mem- ber dan member function dapat diakses oleh derived classes (secara rekursis) dari class ini, namun tidak dapat diakses dari class lainnya. Atau dengan kata lain, data protected bersifat public ke derived classes, dan bersifat private bagi lainnya. Sebagai contoh, kita perlu Stack’s contructor untuk dipanggil oleh ArrayStack dan ListStack, tetapi kita

Perhatikan pula, bahwa saya membuat data member pada Stack pri- vate, bukannya protected. Walaupun terdapat debat soal point ini, se- bagai acuan, Anda seharusnya tidak pernah memperbolehkan sebuah class untuk mengakses data class lain, meskipun antar classes inher- itance. Apabila tidak, jika Anda mengganti implementasi pada base class, maka Anda juga akan mempelajari dan mengganti semua imple- mentasi pada derived classes, tentunya melanggar aturan modularitas.

3. Interface dari derived class secara otomatis termasuk semua fungsi public yang terdefinisi pada base class, tanpa harus secara eksplisit mendaftarkan mereka didalam derived class. Jadi meskipun, kita tidak mendefinisikan NumPushed() didalam ArrayStack, kita tetap dapat memanggil-nya:

ArrayStack *s = new ArrayStack(17); ASSERT(s->NumPushed() == 0); // sould be initialized to 0

4. Sebaliknya, meskipun kita telah mendefinisikan Stack::Push(), namun ia dideklarasikan sebagai virtual; sehingga jika kita memanggil Push() pada objek ArrayStack, maka kita akan mendapatkan versi Push milik ArrayStack:

Stack *s = new ArrayStack(17); if (!s->Full()) // ArrayStack::Full

s->Push(5); // ArrayStack::Push

5. Stack::NumPushed() bukanlah virtual. Hal ini berarti bahwa ia tidak dapat didefinisikan kembali oleh Stack’s derived classes. Beberapa orang berpendapat bahwa Anda seharusnya membuat semua fungsi dalam base class sebagai virtual; dengan demikian, jika di kemudian hari Anda ingin mengimplementasikan sebuah derived class yang mendefin- isikan ulang sebuah fungsi, Anda tidak perlu mengubah base class un- tuk melakukan hal tersebut.

6. Member functions dalam sebuah derived class dapat secara eksplisit memanggil public atau protected functions dalam base class, dengan memanggil nama fungsi tersebut, Base::Function(), seperti contoh berikut ini:

void ArrayStack::Push(int value) {

... Stack::Push(); // invoke base class to increment numPushed

} Tentunya, jika kita hanya memanggil Push() disini (tanpa menam-

bahkan STack::), kompiler akan berfikir kita sedang mengacu ke Ar- rayStack’s Push(), dan hal ini adalah recursif, yang tentunya bukanlah hal yang kita inginkan disini.

Wow! Inheritance didalam C++ menyangkut banyak hal detail. Namun, hal yang kurang dari C++ adalah kecendrungannya untuk membuat im- plementasi file tersebar ke beberapa file; jika Anda memiliki sebuah pohon inheritance yang dalam, akan butuh usaha yang serius untuk mengetahui koding mana yang sebenarnya dieksekusi ketika sebuah member function di- panggil.

Jadi pertanyaan yang perlu dipertanyakan kembali sebelum menggunakan inheritance adalah: apa tujuan Anda? Apakah menulis program dengan jumlah karakter sedikit mungkin? Jika ya, inheritance menjadi berguna, tetapi hal yang sama dapat dilakukan dengan mengubah semua fungsi dan nama variabel menjadi satu karakter saja ”a”, ”b”, ”c” (hanya bercanda). Pointnya adalah, mudah untuk menulis koding yang sukar dibaca apabila menggunakan inheritance.

Jadi kapan waktu yang baik untuk menggunakan inheritance dan kapan ia harus dihindari? Acuan saya adalah hanya menggunakan-nya untuk merep- resentasikan sifat-berbagi antar objek, dan tidak pernah menggunakan-nya untuk menrepresentasikan berbagi-implementasi. Dengan C++, Anda dapat menggunakan inheritance untuk kedua konsep, namun hanya yang pertama yang akan merujuk ke implementasi yang sederhana.

Untuk mengilustrasikan perbedaan antara sifat-berbagi dengan berbagi- implementasi, seumpamanya Anda memiliki banyak macam objek yang Anda butuhkan untuk ditaruh pada lists. Sebagai contoh, hampir semua didalam sebuah sistem operasi menggunakan semacam lists: buffers, threads, users, terminals, dan lain-lain.

Suatu pendekatan yang umum pada masalah ini (umumnya pada pro- grammer yang baru mengenal PBO - pemrograman berorientasi objek) adalah Suatu pendekatan yang umum pada masalah ini (umumnya pada pro- grammer yang baru mengenal PBO - pemrograman berorientasi objek) adalah

Kesimpulan, jika dua classes berbagi paling tidak beberapa member func- tion - yang mana, memiliki sifat sama, dan jika terdapat koding yang hanya bergantung pada sifat-berbagi, maka terdapat keuntungan dalam menggu- nakan inheritance. Dalam Nachos, locks tidak merupakan turunan dari semaphores, walaupun locks di-implementasikan dengan semaphores. Op- erasi pada semaphores dan locks berbeda. Bahkan, inheritance hanya di- gunakan untuk beberapa jenis lists (sorted, keyed, dan lain-lain), dan untuk beberapa implementasi berbeda dari abstraksi fisik-disk, untuk merefleksikan apakah disk memiliki sebuah track-buffer, dan lain-lain. Sebuah disk digu- nakan dengan cara yang sama, tanpa memperdulikan apakah ia memiliki se- buah track-buffer; perbedaannya hanya terletak pada karakteristik perfoma- nya.

4.2 Templates

Templates adalah konsep yang berguna di C++, namun juga berbahaya. Dengan Templates, Anda dapat melakukan parameterisasi sebuah definisi class dengan katakunci type, untuk memungkinkan Anda menulis koding yang generik dan type-independent. Sebagai contoh, Implementasi Stack kita diatas hanya bekerja untuk pushing dan popping integers; bagaimana jika kita ingin sebuah stack untuk characters, atau floats, atau pointers, atau suatu struktur data tertentu?

Dalam C++, hal ini dengan mudah dapat dilakukan dengan templates: template <class T>

class Stack { public: Stack(int sz); ~Stack(); void Push(T value); bool Full();

private: int size; private: int size;

Untuk mendefinisikan sebuah template, kita menambahkan katakunci template pada definisi class tersebut, dan kita menaruh tipe yang di-parameterisasi untuk template tersebut didalam kurung sudut. Jika kita membutuhkan un- tuk parameterisasi implementasi dengan dua atau lebih tipe, maka ia bekerja seperti layaknya sebuah list argument: template <class T, class S>. Kita da- pat menggunakan type-prameters dimanapun dalam definisi tersebut, persis seperti jika mereka adalah tipe biasa.

Ketiak kita menyediakan implementasi tersebut untuk setiap member functions didalam class, kita juga harus mendeklarasikan mereka sebagai templates, dan sekali lagi, sekali kita melakukan hal tersebut, kita dapat menggunakan tipe parameters tersebut hanya seperti tipe biasa:

// template version of Stack::Stack template <class T> Stack<T>::Stack(int sz) {

size = sz; top = 0; stack = new T[size]; //Let’s get an array of type T

} // template version of Stack::Push

template <class T> void Stack<T>::Push(T value) {

ASSERT(!Full()); stack[top++] = value;

Membuat sebuah objek dari sebuah class template sama dengan membuat objek biasa:

void test() { Stack<int> s1(17); Stack<char> *s2 = new Stack<char>(23);

s1.Push(5); s2->Push(’z’); delete s2;

Segala sesuatu berjalan seperti jika kita mendefinisikan dua classes, satu diberinama Stack<int> – sebuah stack untuk integers, dan satu lagi diberi- nama Stack<char> – sebuah stack untuk characters. s1 bersikap sama seperti sebuah instan dari yang pertama; s2 bersikap juga sama seperti se- buah instan dari yang kedua. Bahkan, hal ini sama persis dengan bagaimana templates secara tipikal diimplementasikan – Anda memperoleh kopi koding keseluruhan dari template tersebut untuk setiap tipe instant yang berbeda. Pada contoh diatas, kita mendapatkan satu kopi dari koding untuk ints dan satu kopi koding untuk chars.

Jadi apa salahnya menggunakan template? Anda selalu diajarkan untuk membuat koding Anda se-modular mungkin, sehingga ia dapat digunakan kembali, jadi semuanya seharusnya dibuat menjadi template, ya-kan? Salah.

Prinsip masalah-nya dengan template adalah mereka dapat membuat de- bugging menjadi sangat sulit - templates mudah digunakan jika mereka ber- jalan baik, tetapi menemukan sebuah bug didalam mereka menjadi sulit. Hal ini sebagian disebabkan karenan generasi C++ debuggers sekarang tidak-lah mengerti benar-benar tentang templates. Namun, tetap lebih mudah men- debug sebuah template daripada dua implementasi yang hampir sama dan hanya berbeda pada tipe data mereka.

Jadi saran terbaik adalah - jangan menggunakan sebuah class didalam sebuah template, kecuali benar-benar terdapat sebuah term dekat, digu- nakan untuk template tersebut. Dan jika Anda benar-benar butuh untuk mengimplementasikan sebuah template, maka implementasikan dan debug sebuah versi non-template terlebih dahulu. Setelah berjalan, maka tidak ter- lalu sulit untuk mengubahnya ke sebuah versi template. Hal yang kemudian Anda harus kuatirkan adalah eksplosi koding - sebagai contoh, besar objek program Anda sekarang menjadi orde megabytes, dikarenakan oleh 15 kopi dari hash tabel/list/... routines, satu untuk setiap tipe yang Anda inginkan ditaruh didalam sebuah hash table/list/... (Ingat, Anda memiliki kompiler yang tidak bersahabat!).

5 Fitur-fitur yang perlu dihindari seperti wabah

Meskipun artikel ini cukup panjang, masih banyak fitur-fitur di C++ yang belum sempat saya bahas. Saya yakin setiap fitur memiliki kepentingannya masing-masing, namun meskipun telah melakukan pemrograman di C dan C++ untuk lebih dari 15 tahun, saya belum pernah menemukan sebuah alasan yang mengena untuk menggunakannya di dalam koding yang saya telah tulis (diluar dari kelas bahasa pemrograman!).

Namun, ada alasan-alasan tertentu untuk menghindari penggunaan fitur- Namun, ada alasan-alasan tertentu untuk menghindari penggunaan fitur-

Saya tidak menggunakan fitur-fitur berikut ini pada program Nachos. Jika Anda menggunakannya, caveat hacker (berhati-hati terhadap penggu- naannya).

1. Multiple Inheritance. Suatu hal yang memungkinkan di C++ untuk mendefinisikan sebuah class yang mewarisi sifat dari beberapa classes (sebagai contoh, seekor anjing adalah sebuah binatang dan juga sebuah benda yang berbulu). Jika programs yang menggunakan single inher- itance dapat menjadi sulit untuk dimengerti, maka programs dengan multiple inheritance dapat menjadi membingungkan.

2. References. Variabel Reference secara umum sulit untuk dimengerti; mereka berperan sama seperti pointers, dengan sintaks yang sedikir berbeda (sangat disayangkan, saya tidak sedang bercanda!). Mereka sering digunakan untuk emndeklarasikan beberapa parameters ke se- buah fungsi sebaga reference parameters, seperti pada Pascal. Sebuah call-by-reference parameter dapat dimodifikasi oleh si fungsi pemang- gil, tanpa si pemanggil harus melemparkan sebuah pointer. Akibatnya adalah parameter tersebut seperti dipanggil secara by value (sehingga tidak dapat diubah), tetapi pada kenyataannya dapat diubah secara tranparan oleh fungsi yang dipanggil. Secara nyata, hal ini dapat men- jadi sumber ketidak-jelasan bugs, belum lagi kenyataan bahwa seman- tik dari references pada C++ secara umum tidaklah jelas.

3. Operator overloading. C++ memperbolehkan Anda mendefinisikan- ulang fungsi dari operators (seperti + dan ¿¿) untuk objek pada class. Hal ini berbahaya (”implementasi mana dari ’+’ yang dimaksud?”), dan ketika digunakan dalam cara yang tidak-berintuisi, menjadi sumber kebingungan yang besar, diperburuk dengan kenyataan bahwa C++ melakukan konversi type secara implisit, yang dapat mempengaruhi op- erator mana yang akan dipanggil. Sayangnya, fasilitas I/O C++ meng- gunakan banyak operator overloading dan references, sehingga Anda tidak dapat menghindari-nya, tetapi pikir dua-kali, sebelum Anda mendefinisikan- ulang ’+’ menjadi ”operator penggabungan dua strings”.

4. Function overloading. Anda juga dapat mendefinisikan fungsi-fungsi yang berbeda dalam sebuah class dengan nama yang sama tetapi tipe 4. Function overloading. Anda juga dapat mendefinisikan fungsi-fungsi yang berbeda dalam sebuah class dengan nama yang sama tetapi tipe

5. Standard template library. Sebuah standar ANSI telah muncul seba- gai sebuah rutin librari, yang mengimplementasikan banyak hal seperti lists, hash tables, dan lain-lain; hal ini disebut dengan STL (Stan- dard Template Library). Menggunakan sebuah librari seperti ini se- harusnya membuat pemrograman menjadi sederhana jika struktur data yang Anda butuhkan telah tersedia didalam librari tersebut. Namun, STL mendorong penggunaan legal C++, dan secara kenyataan tidak ada kompiler (termasuk g++) yang dapat mendukung-nya sekarang. Belum lagi bahwa legal C++ menggunakan references, operator over- loading dan function overloading.