C++ Secara Mendalam

Tutorial Bahasa C++

Bagian awal tutorial ini membahas materi dasar yang sudah disajikan dalam dua modul terakhir, dan memberikan lebih banyak informasi tentang konsep lanjutan. Fokus kita dalam modul ini adalah memori dinamis, dan detail selengkapnya tentang objek dan class. Beberapa topik lanjutan juga diperkenalkan, seperti pewarisan, polimorfisme, template, pengecualian, dan namespace. Kita akan mempelajari ini nanti di materi Advanced C++.

Desain Berorientasi Objek

Ini adalah tutorial yang sangat baik tentang desain berorientasi objek. Kami akan menerapkan metodologi yang disajikan di sini dalam project modul ini.

Belajar dari Contoh #3

Fokus kita dalam modul ini adalah mendapatkan lebih banyak latihan dengan pointer, desain berorientasi objek, array multi-dimensi, dan class/objek. Pelajari contoh-contoh berikut. Kita tidak boleh terlalu menekankan bahwa kunci untuk menjadi programmer yang baik adalah latihan, latihan, latihan.

Latihan #1: Lebih Banyak Berlatih dengan Pointer

Jika Anda memerlukan latihan tambahan terkait pointer, baca resource ini yang mencakup semua aspek pointer dan menyediakan banyak contoh program.

Apa output dari program berikut ini? Jangan jalankan program, tetapi gambar gambar memori untuk menentukan outputnya.

void Unknown(int *p, int num);
void HardToFollow(int *p, int q, int *num);

void Unknown(int *p, int num) {
  int *q;

  q = #
  *p = *q + 2;
  num = 7;
}

void HardToFollow(int *p, int q, int *num) {
  *p = q + *num;
  *num = q;
  num = p;
  p = &q;
  Unknown(num, *p);
}

main() {
  int *q;
  int trouble[3];

  trouble[0] = 1;
  q = &trouble[1];
  *q = 2;
  trouble[2] = 3;

  HardToFollow(q, trouble[0], &trouble[2]);
  Unknown(&trouble[0], *q);

  cout << *q << " " << trouble[0] << " " << trouble[2];
}

Setelah menentukan output secara manual, jalankan program untuk melihat apakah Anda benar.

Latihan #2: Lebih Banyak Praktik dengan Class dan Objek

Jika Anda memerlukan latihan tambahan dengan class dan objek, di sini adalah resource yang melalui implementasi dua class kecil. Luangkan waktu untuk melakukan latihan.

Latihan #3: Array Multi-Dimensi

Pertimbangkan program berikut: 

const int kStudents = 25;
const int kProblemSets = 10;

// This function returns the highest grade in the Problem Set array.
int get_high_grade(int *a, int cols, int row, int col) {
  int i, j;
  int highgrade = *a;

  for (i = 0; i < row; i++)
    for (j = 0; j < col; j++)
      if (*(a + i * cols + j) > highgrade)  // How does this line work?
        highgrade = *(a + i*cols + j);
  return highgrade;
}

int main() {
 int grades[kStudents][kProblemSets] = {
   {75, 70, 85, 72, 84},
   {85, 92, 93, 96, 86},
   {95, 90, 83, 76, 97},
   {65, 62, 73, 84, 73}
 };
 int std_num = 4;
 int ps_num = 5;
 int highest;

 highest = get_high_grade((int *)grades, kProblemSets, std_num, ps_num);
 cout << "The highest problem set score in the class is " << highest << endl;

 return 0;
}

Terdapat baris dalam program ini yang bertuliskan "Bagaimana cara kerja baris ini?" - bisakah kamu mengetahuinya? Berikut adalah penjelasan kami.

Tulis program yang menginisialisasi array 3 dimensi dan mengisi nilai dimensi ke-3 dengan jumlah ketiga indeks. Berikut solusi kami.

Latihan #4: Contoh Desain OO yang Luas

Berikut adalah contoh desain berorientasi objek terperinci yang menjalani seluruh proses dari awal hingga akhir. Kode akhir ditulis dalam bahasa pemrograman Java, tetapi Anda akan dapat membacanya mengingat seberapa jauh Anda telah melangkah.

Harap luangkan waktu untuk mempelajari seluruh contoh ini. Ini adalah ilustrasi yang bagus tentang proses, dan alat desain yang mendukungnya.

Pengujian Unit

Pengantar

Pengujian adalah bagian penting dari proses rekayasa perangkat lunak. Pengujian unit adalah jenis pengujian tertentu, yang memeriksa fungsionalitas satu modul kecil kode sumber.Pengujian unit selalu dilakukan oleh engineer, dan biasanya dilakukan bersamaan dengan coding modul. Driver pengujian yang Anda gunakan untuk menguji class Composer dan Database adalah contoh pengujian unit.

Pengujian Unit memiliki karakteristik berikut. Mereka...

  • menguji komponen secara terpisah
  • bersifat determenistik
  • biasanya dipetakan ke satu class
  • menghindari dependensi pada sumber daya eksternal, mis. {i>database<i}, file, jaringan
  • jalankan dengan cepat
  • dapat dijalankan dalam urutan apa pun

Ada framework dan metodologi otomatis yang memberikan dukungan serta konsistensi untuk pengujian unit di organisasi software engineering yang besar. Ada beberapa framework pengujian unit open source yang canggih, yang akan kita pelajari nanti dalam pelajaran ini. 

Pengujian yang terjadi sebagai bagian dari pengujian unit diilustrasikan di bawah ini.

Dalam kondisi ideal, kami menguji hal berikut:

  1. Antarmuka modul diuji untuk memastikan informasi mengalir masuk dan keluar dengan benar.
  2. Struktur data lokal diperiksa untuk memastikan penyimpanan data dengan benar.
  3. Kondisi batas diuji untuk memastikan modul beroperasi dengan benar pada batas yang membatasi atau membatasi pemrosesan.
  4. Kami menguji jalur independen melalui modul untuk memastikan setiap jalur, dan setiap pernyataan dalam modul, dijalankan setidaknya satu kali. 
  5. Akhirnya, kita perlu memeriksa apakah {i>error<i} telah ditangani dengan benar.

Cakupan Kode

Pada kenyataannya, kami tidak dapat mencapai "cakupan kode" yang lengkap dengan pengujian kami. Cakupan kode adalah metode analisis yang menentukan bagian mana dari sistem software yang telah dijalankan (dicakup) oleh rangkaian kasus pengujian dan bagian mana yang belum dijalankan. Jika kita mencoba dan mencapai cakupan 100%, kita akan menghabiskan lebih banyak waktu untuk menulis pengujian unit daripada menulis kode yang sebenarnya. Pertimbangkan untuk membuat pengujian unit untuk semua jalur independen berikut ini. Masalah ini dapat dengan cepat menjadi masalah eksponensial.

Dalam diagram ini, garis merah tidak diuji, sedangkan garis yang tidak berwarna diuji.

Alih-alih mencoba cakupan 100%, kami berfokus pada pengujian yang meningkatkan keyakinan kami bahwa modul berfungsi dengan baik. Kami menguji hal-hal seperti:

  • Kasus null
  • Pengujian rentang, misalnya, tes nilai positif/negatif
  • Kasus ekstrem
  • Kasus kegagalan
  • Menguji jalur yang paling sering dijalankan

Framework Pengujian Unit

Sebagian besar framework pengujian unit menggunakan pernyataan untuk menguji nilai selama eksekusi jalur. Pernyataan adalah pernyataan yang memeriksa apakah suatu kondisi benar atau tidak. Hasil pernyataan dapat berupa keberhasilan, kegagalan nonfatal , atau kegagalan fatal. Setelah pernyataan dijalankan, program akan berlanjut secara normal jika hasilnya sukses atau kegagalan nonfatal. Jika terjadi kegagalan fatal, fungsi saat ini akan dibatalkan.

Pengujian terdiri dari kode yang menyiapkan status atau memanipulasi modul Anda, ditambah dengan sejumlah pernyataan yang memverifikasi hasil yang diharapkan. Jika semua pernyataan dalam pengujian berhasil, yaitu menampilkan true, maka pengujian akan berhasil. Jika tidak, pengujian akan gagal.

Satu kasus pengujian berisi satu atau beberapa pengujian. Kami mengelompokkan pengujian ke dalam kasus pengujian yang mencerminkan struktur kode yang diuji. Dalam kursus ini, kita akan menggunakan CPPUnit sebagai framework pengujian unit. Dengan framework ini, kita dapat menulis pengujian unit di C++ dan menjalankannya secara otomatis, sehingga memberikan laporan tentang keberhasilan atau kegagalan pengujian.

Penginstalan CPPUnit

Download kode CPPUnit dari SourceForge. Temukan direktori yang sesuai dan tempatkan file tar.gz di sana. Kemudian, masukkan perintah berikut (di Linux, Unix), dengan mengganti nama file cppunit yang sesuai:

gunzip filename.tar.gz
tar -xvf filename.tar

Jika menggunakan Windows, Anda mungkin perlu menemukan utilitas untuk mengekstrak file tar.gz. Langkah berikutnya adalah mengompilasi library. Ubah ke direktori cppunit. Di sana ada file INSTALL yang memberikan instruksi spesifik. Biasanya, Anda perlu menjalankan:

./configure
make install

Jika Anda mengalami masalah, lihat file INSTALL. Library biasanya ditemukan di direktori cppunit/src/cppunit. Untuk memeriksa apakah kompilasinya berfungsi, buka direktori cppunit/examples/simple dan ketik "make". Jika semuanya berjalan lancar, berarti Anda sudah siap.

Tersedia tutorial yang sangat baik di sini. Ikuti tutorial ini dan buat class bilangan kompleks, serta pengujian unit yang terkait. Ada beberapa contoh tambahan dalam direktori cppunit/examples.

Mengapa Saya Harus Melakukan Ini?

Pengujian unit sangat penting dalam industri karena beberapa alasan. Anda sudah mengetahui salah satu alasan berikut: Kami memerlukan cara untuk memeriksa pekerjaan kita saat mengembangkan kode. Bahkan saat mengembangkan program yang sangat kecil, kami secara naluri menulis semacam pemeriksa atau driver untuk memastikan bahwa program kami melakukan hal yang diharapkan.

Berdasarkan pengalaman panjang, para engineer tahu bahwa peluang sebuah program akan berfungsi pada percobaan pertama sangatlah kecil. Pengujian unit didasarkan pada ide ini dengan membuat program pengujian melakukan pemeriksaan mandiri dan dapat diulang. Pernyataan tersebut menggantikan pemeriksaan output secara manual. Selain itu, karena mudah untuk menafsirkan hasilnya (pengujian lulus atau gagal), pengujian dapat dijalankan berulang kali, sehingga memberikan jaring pengaman yang membuat kode Anda lebih tahan terhadap perubahan.

Mari kita bahas secara konkret: Saat Anda pertama kali mengirimkan kode yang sudah selesai ke CVS, kode tersebut akan berfungsi dengan sempurna. Dan tetap berfungsi dengan sempurna untuk sementara waktu. Kemudian suatu hari, orang lain mengubah kode Anda. Cepat atau lambat seseorang akan memecahkan kode Anda. Apa kamu kira mereka akan menyadari dengan sendirinya? Tidak mungkin. Namun, saat Anda menulis pengujian unit, ada sistem yang dapat menjalankannya, secara otomatis, setiap hari. Ini disebut sistem continuous integration. Jadi, saat engineer X itu memecahkan kode Anda, sistem akan mengirim email jahat kepadanya hingga mereka memperbaikinya. Meskipun engineer X adalah ANDA!

Selain membantu Anda mengembangkan software, serta menjaga keamanan software tersebut dalam menghadapi perubahan, pengujian unit:

  • Membuat spesifikasi yang dapat dieksekusi, dan dokumentasi yang tetap sinkron dengan kode. Dengan kata lain, Anda dapat membaca pengujian unit untuk mempelajari perilaku yang didukung modul tersebut.
  • Membantu Anda memisahkan persyaratan dari penerapan. Karena Anda menegaskan perilaku yang terlihat secara eksternal, Anda mendapat kesempatan untuk memikirkannya secara eksplisit alih-alih mencampurkan ide tentang cara menerapkan perilaku tersebut.
  • Mendukung eksperimen. Jika Anda memiliki jaring pengaman untuk memperingatkan saat perilaku modul rusak, Anda akan memiliki kemungkinan untuk mencoba berbagai hal dan mengonfigurasi ulang desain.
  • Memperbaiki desain Anda. Menulis pengujian unit secara menyeluruh sering kali mengharuskan Anda menjadikan kode lebih mudah diuji. Kode yang dapat diuji sering kali lebih modular daripada kode yang tidak dapat diuji.
  • Menjaga kualitas tetap tinggi. Bug kecil dalam sistem penting dapat menyebabkan perusahaan kehilangan jutaan dolar, atau lebih buruk lagi, kepuasan atau kepercayaan pengguna. Jaring pengaman yang disediakan oleh pengujian unit akan memperkecil kemungkinan ini. Dengan mendeteksi bug lebih awal, mereka juga memungkinkan tim UM (Uji Mutu) menghabiskan waktu pada skenario kegagalan yang lebih rumit dan sulit, daripada melaporkan kegagalan yang jelas.

Luangkan waktu untuk menulis pengujian unit menggunakan CPPUnit untuk aplikasi database Composer. Lihat direktori cppunit/examples/ untuk mendapatkan bantuan.

Cara Kerja Google

Pengantar

Bayangkan seorang biksu pada Abad Pertengahan melihat ribuan manuskrip di arsip biaranya.“Mana yang dinyanyikan Aristotle...”

perpustakaan monaster

Untungnya, manuskrip-manuskrip ini diatur berdasarkan konten dan ditulis dengan simbol-simbol khusus untuk memudahkan pengambilan informasi yang terkandung di dalamnya. Tanpa pengaturan seperti itu, akan sangat sulit untuk menemukan manuskrip yang relevan.

Aktivitas menyimpan dan mengambil informasi tertulis dari koleksi besar disebut Pengambilan Informasi (IR). Aktivitas ini menjadi semakin penting selama berabad-abad, terutama dengan penemuan seperti kertas dan mesin cetak. Dulu, bangunan ini hanya dapat ditempati beberapa orang. Namun, sekarang, ratusan juta orang terlibat dalam pengambilan informasi setiap hari saat menggunakan mesin telusur atau menelusuri desktop.

Mulai Pengambilan Informasi

kucing di topi

Dr. Seuss menulis 46 buku anak-anak selama 30 tahun. Buku-bukunya menceritakan tentang kucing, sapi, dan gajah, tentang siapa, grinch, dan lorax. Apa kamu ingat makhluk mana yang ada dalam cerita apa? Kecuali Anda adalah orang tua, hanya anak-anak yang dapat memberi tahu Anda rangkaian cerita Dr. Seuss mana yang memiliki makhluk hidup:

(COW dan BEE) atau CROWS

Kami akan menerapkan beberapa model pengambilan informasi klasik untuk membantu kami mengatasi masalah ini.

Pendekatan yang jelas adalah brute force: Dapatkan ke-46 cerita Dr. Seuss, dan mulailah membaca. Untuk setiap buku, perhatikan kata mana yang berisi kata COW dan BEE, dan pada saat yang sama, cari buku yang berisi kata CROWS. Komputer jauh lebih cepat dalam hal ini. Jika kita memiliki semua teks dari buku Dr. Seuss dalam bentuk digital, misalkan sebagai file teks, kita cukup melakukan grep pada file-file tersebut. Untuk koleksi kecil seperti buku Dr. Seuss, teknik ini sudah cukup bagus.

Namun, ada banyak situasi saat kita membutuhkan lebih banyak hal. Misalnya, pengumpulan semua data yang saat ini online terlalu besar untuk ditangani oleh grep. Kami juga tidak ingin hanya ingin dokumen yang cocok dengan kondisi kami. Namun, kami sudah terbiasa memberikan peringkat sesuai dengan relevansinya.

Pendekatan lain selain grep adalah membuat indeks dokumen dalam koleksi sebelum melakukan penelusuran. Indeks di IR mirip dengan indeks di bagian belakang buku teks. Kami membuat daftar semua kata (atau istilah) dalam setiap kisah Dr. Seuss, dengan mengecualikan kata-kata seperti “the”, “and”, dan kata penghubung, preposisi, dll. (ini disebut stop-word). Selanjutnya, kami merepresentasikan informasi ini dengan cara yang memfasilitasi penemuan istilah dan mengidentifikasi kisah yang memuatnya.

Salah satu representasi yang mungkin adalah matriks dengan cerita di bagian atas, dan istilah yang tercantum di setiap baris. Angka “1” di kolom menunjukkan bahwa istilah tersebut muncul dalam artikel untuk kolom tersebut.

tabel buku dan kata

Kita dapat melihat setiap baris atau kolom sebagai vektor bit. Vektor bit baris menunjukkan di mana istilah tersebut muncul. Vektor bit kolom menunjukkan istilah apa yang muncul dalam cerita.

Kembali ke masalah awal:

(COW dan BEE) atau CROWS

Kita mengambil vektor bit untuk istilah-istilah ini dan terlebih dahulu melakukan AND dengan bit-wise, lalu melakukan OR dengan bit-bijaksana pada hasilnya.

(100001 dan 010011) atau 000010 = 000011

Jawabannya: “Pak Bambang Bisa Moo! Dapatkah Anda?” dan “The Lorax”. Ini adalah ilustrasi model Pengambilan Boolean, yang merupakan model “pencocokan persis”.

Misalkan kita memperluas matriks untuk menyertakan semua cerita Dr. Seuss dan semua istilah yang relevan dalam ceritanya. Matriks akan berkembang pesat, dan pengamatan penting adalah sebagian besar entri akan menjadi 0. Matriks mungkin bukan representasi terbaik untuk indeks. Kita perlu menemukan cara untuk menyimpan angka 1 saja.

Beberapa Peningkatan

Struktur yang digunakan pada IR untuk mengatasi masalah ini disebut indeks terbalik. Kami menyimpan kamus istilah, lalu untuk setiap istilah, kami memiliki daftar yang mencatat dokumen yang memuat istilah tersebut. Daftar ini disebut daftar postingan. Daftar tertaut tunggal berfungsi dengan baik untuk mewakili struktur ini seperti yang ditunjukkan di bawah ini.

Jika belum familier dengan daftar tertaut, cukup telusuri daftar tertaut di Google dengan menelusuri "daftar tertaut di C++", dan Anda akan menemukan banyak referensi yang menjelaskan cara membuatnya dan cara penggunaannya. Kita akan membahas hal ini secara lebih mendetail di modul selanjutnya.

Perhatikan bahwa kami menggunakan ID Dokumen (DocIDs), bukan nama artikel. Kami juga mengurutkan DocID ini karena memfasilitasi pemrosesan kueri.

Bagaimana kita memproses kueri? Untuk masalah asal, pertama-tama kita temukan daftar postingan COW, lalu daftar postingan BEE. Kemudian, kita “menggabungkannya” menjadi satu:

  1. Simpan penanda ke dalam kedua daftar dan telusuri kedua daftar postingan secara bersamaan.
  2. Di setiap langkah, bandingkan DocID yang ditunjuk oleh kedua pointer.
  3. Jika sama, masukkan DocID tersebut dalam daftar hasil, atau teruskan pointer yang menunjuk ke docID yang lebih kecil.

Berikut ini cara kita membuat indeks terbalik:

  1. Tetapkan DocID untuk setiap dokumen yang diinginkan.
  2. Untuk setiap dokumen, identifikasi istilah yang relevan (tokenize).
  3. Untuk setiap istilah, buat catatan yang terdiri dari istilah, DocID tempat istilah ditemukan, dan frekuensi dalam dokumen tersebut. Perhatikan bahwa mungkin saja ada beberapa data untuk istilah tertentu jika istilah tersebut muncul di lebih dari satu dokumen.
  4. Urutkan data berdasarkan istilah.
  5. Buat daftar kamus dan postingan dengan memproses data tunggal untuk sebuah istilah, dan juga menggabungkan beberapa catatan untuk istilah yang muncul di lebih dari satu dokumen. Buat daftar DocID tertaut (dalam urutan yang diurutkan). Setiap istilah juga memiliki frekuensi yang merupakan jumlah frekuensi di semua catatan untuk satu istilah.

Proyek

Temukan beberapa dokumen teks biasa yang panjang yang dapat digunakan untuk bereksperimen. Project ini adalah membuat indeks terbalik dari dokumen, menggunakan algoritma yang dijelaskan di atas. Anda juga harus membuat antarmuka untuk input kueri dan mesin untuk memprosesnya. Anda dapat menemukan partner proyek di forum tersebut.

Berikut adalah kemungkinan proses untuk menyelesaikan proyek ini:

  1. Hal pertama yang harus dilakukan adalah menentukan strategi untuk mengidentifikasi istilah dalam dokumen. Buatlah daftar semua kata perhentian yang dapat Anda pikirkan, dan tulis fungsi yang membaca kata-kata dalam file, menyimpan istilah, dan menghilangkan kata perhentian. Anda mungkin harus menambahkan lebih banyak kata perhentian ke daftar saat meninjau daftar istilah dari iterasi.
  2. Tulis kasus pengujian CPPUnit untuk menguji fungsi Anda, dan makefile untuk menyatukan semuanya untuk build Anda. Periksa file Anda ke dalam CVS, terutama jika Anda bekerja sama dengan partner. Sebaiknya Anda mencari tahu cara membuka instance CVS untuk engineer jarak jauh.
  3. Menambahkan pemrosesan untuk menyertakan data lokasi, yaitu file yang mana dan di mana letak istilah dalam file? Anda mungkin ingin mengetahui perhitungan untuk menentukan nomor halaman atau nomor paragraf.
  4. Tulis kasus pengujian CPPUnit untuk menguji fungsi tambahan ini.
  5. Buat indeks terbalik dan simpan data lokasi di setiap catatan istilah.
  6. Menulis lebih banyak kasus pengujian.
  7. Desain antarmuka yang memungkinkan pengguna memasukkan kueri.
  8. Dengan menggunakan algoritme penelusuran yang dijelaskan di atas, proses indeks terbalik dan tampilkan data lokasi kepada pengguna.
  9. Pastikan untuk menyertakan kasus pengujian untuk bagian akhir ini juga.

Seperti yang telah kami lakukan pada semua project, gunakan forum dan chat untuk menemukan partner project dan berbagi ide.

Fitur Tambahan

Langkah pemrosesan yang umum di banyak sistem IR disebut stemming. Ide utama di balik stemming adalah bahwa pengguna yang menelusuri informasi terkait “pengambilan” juga akan tertarik pada dokumen yang memiliki informasi yang berisi “pengambilan”, “diambil”, “pengambilan”, dan sebagainya. Sistem rentan terhadap error karena stemming yang buruk, sehingga hal ini agak rumit. Misalnya, pengguna yang tertarik dengan "pengambilan informasi" mungkin mendapatkan dokumen berjudul "Informasi tentang Golden Retriever" karena adanya stemming. Algoritme yang berguna untuk stemming adalah algoritma Porter.

Aplikasi: Ke mana saja!

Lihat penerapan konsep ini di Panoramas.dk.