Yêu cầu trước khi đọc: học xong Lập trình C/C++ căn bản BÀI 5: TEMPLATE (TIẾP) part

Một phần của tài liệu LẬP TRÌNH C/C++ NÂNG CAO potx (Trang 30 - 41)

Lại đau đầu

Ta muốn viết một chương trình tìm kiếm phần tử trong một mảng. Ta viết như sau

CODE

template<class T>int search(T a[],int n,T key) {

int index=0;

while(index<n && a[index] != key) index++; if(index == n) return -1;else return index; }

Sau đó trong hàm main ta viết

CODE

char *list[]={"zero","one","two"}; //thực ra là mảng 2 chiều thôi search(list,3,"two"); //ồ không, lại so sánh memory address nữa rồi

Nhưng lần này vấn đề phức tạp hơn nhiều. Ví dụ nếu là mảng các Person là đụng thêm vấn đề cấp phát bộ nhớ nữa

Giải quyết

Chương trình dưới đây trình bày cách tạo một lớp mảng template, với đủ các chức năng tạo, thêm, truy xuất dữ liệu, toán tử [].

Đặc biệt là giải quyết đau đầu tìm kiếm dữ liệu ở trên vì so sánh memory address. Lưu ý là khi tạo ta phải dùng reference refers to

pointer để cấp phát bộ nhớ đó

CODE

#include <iostream> using namespace std;

template<class T>class Array {

T* array;int size; public:

Array(int n); ~Array();

void setValue(const T&,int n); //thiết lập dữ liệu T& getValue(int n); //truy xuất dữ liệu

void makeArray(T *&arr,int n); //tạo mảng

T& operator[](int i); //toán tử [] truy xuất dữ liệu mảng int seek(const T& key); //tìm kiếm trong mảng gọi hàm

int search(const T* list,int size,const T key); //tìm kiếm trong mảng có sẵn };

template<typename T>Array<T>::Array(int n) {

size=n;

array = new T[size]; }

template<typename T>Array<T>::~Array() {

delete [] array; }

template<typename T>void Array<T>::setValue(const T& value,int n) {

*(array+n) = value; }

template<typename T>T& Array<T>::getValue(int n) {

return *(array+n); }

template<typename T>void Array<T>::makeArray(T *&arr,int n) {

arr = new T[n]; }

template<typename T>T& Array<T>::operator[](int i) {

return *(array+i); }

template<typename T>int Array<T>::seek(const T& key) {

int index=0;

while((index<size) && *(array+index)!=key) ++index; if(index==size) return -1;

else return index; }

template<typename T>int Array<T>::search(const T* list,int size,const T key) {

int index=0;

while((index<size) && *(list+index)!=key) ++index; if(index==size) return -1;

else return index; } class Person { int age; public: Person(){age=0;} Person(int age){this->age=age;} int getAge() const{return age;}

friend bool operator!=(const Person& p1,const Person& p2) {

return p1.getAge()!=p2.getAge(); }

{ os<<p.getAge()<<endl; return os; } }; int main() { Array<Person> a(3); a.setValue(Person(5),2); cout<<a[2]; Person* b; a.makeArray(b,4);

for(int i=0;i<4;i++) *(b+i)=Person(i+2); cout<<a.seek(Person(5))<<endl; cout<<a.search(b,4,Person(4))<<endl; return 0;

}

Có vẻ đã xong. Hết rắc rối rồi.

Chưa. Vẫn còn 2 rắc rối nữa. Bạn hãy thử viết toán tử output << cho một mảng template class hay so sánh giữa hai mảng

template class như trên thử xem.

Bạn sẽ không viết được đâu nếu không sử dụng cái này: prototype template function (khai báo nguyên mẫu cho hàm template)

(Học mấy cái điên đầu này làm gì nhỉ ? Làm gì à ? Hãy thử cho hai cầu thủ trong một game đá banh đối diện nhau. Họ có bao

nhiêu hành động có thể làm được lúc đó ? Chuyền bóng ? Lừa bóng ? Đốn ? special Zidane-style skill ? Mike Tyson skill ? Hai mảng

các hành động ấy phải đem ra mà chọi lẫn nhau. Bởi thế mang tiếng là “Advance C++” nhưng thực ra trong lập trình game vẫn chỉ

là “newbie”)

prototype template function

Chuẩn bị một tập tin tên là “array.h”

CODE

#ifndef ARRAY_H #define ARRAY_H

#include <iostream> using namespace std;

template<class T>class Array;

template<typename T>bool equal(const Array<T>&,const Array<T>&); template<typename T>ostream& operator<<(ostream&,const Array<T>&); template<class T>class Array

{

T* array;int size; public:

Array(int n); ~Array();

void setValue(const T&,int n);

friend bool equal <>(const Array<T>&,const Array<T>&); friend ostream& operator<< <>(ostream&,const Array<T>&); };

#include "array.cpp" #endif

Chuẩn bị một tập tin tên là “array.cpp”

CODE

template<typename T>Array<T>::Array(int n) {

size=n;

array = new T[size]; }

template<typename T>Array<T>::~Array() {

delete [] array; }

template<typename T>void Array<T>::setValue(const T& value,int n) {

}

template<typename T>bool equal(const Array<T>& a1,const Array<T>& a2) {

return a1.size==a2.size; }

template<typename T>ostream& operator<<(ostream& os,const Array<T>& a) {

for(int i=0;i<a.size;++i) os<<*(a.array+i); return os;

LẬP TRÌNH C/C++ NÂNG CAO

Yêu cầu trước khi đọc: học xong Lập trình C/C++ căn bản BÀI 5: TEMPLATE (TIẾP) part 2 BÀI 5: TEMPLATE (TIẾP) part 2

Cuối cùng là “main.cpp” CODE #include "array.h" class Person { int age; public: Person() { age=0; } Person(int age) { this->age=age; }

int getAge() const {

return age; }

friend bool operator!=(const Person& p1,const Person& p2) {

return p1.getAge()!=p2.getAge(); }

friend ostream& operator<<(ostream& os,const Person& p) {

os<<p.getAge()<<endl; return os; } }; int main() { Array<Person> a(3); a.setValue(Person(24),0); a.setValue(Person(15),1); a.setValue(Person(5),2); cout<<a; Array<Person> b(3); cout<<equal(a,b)<<endl; return 0; }

Giải thích: equal và operator<< đều là hai hàm bạn, do đó để hoạt động cần có sẵn lớp Array. Nhưng lớp Array muốn biên dịch

được phải cần có hai hàm này. Do đó ta phải khai báo prototype của hai hàm này trước. Nhưng vì đây là 2 template function,nên

khi khai báo lại prototype của chúng lần thứ hai trong một class template (ở đây là class Array) ta phải có cái kí hiệu này <> Khi

đó là một prototype template function. Khi đó, thay vì tập tin cpp chứa thân hàm include tập tin header chứa nguyên mẫu của

hàm, ta phải làm ngược lại. Kĩ thuật này hiểu và ứng dụng cực kì rắc rối nhưng khổ nỗi lại áp dụng rất nhiều về sau, đặc biệt khi

làm các game lớn.

Biên dịch lại mã này với GCC

Không bắt buộc, nhưng nên làm nếu như sau này bạn có định làm việc với game trong môi trường *nix và console. Hãy đem 3 tập

tin này (array.h, array.cpp, main.cpp) và thử biên dịch bằng GCC trong Linux thử xem. Nhớ tạo makefile. Trong trường bọn tôi chủ

yếu làm việc bằng GCC và VI trong *nix chứ không phải Window. Việc sử dụng các bộ Visual Studio tuy không bị cấm nhưng

không được khuyến khích. Và bài tập lẫn bài thi đều phải submit nguyên project kèm makefile để biên dịch trong môi trường *nix

hết.

Trong phần trước ta đã xem các ví dụ dùng cách “tham chiếu mà tham chiếu đến con trỏ” Trong phần này chúng ta sẽ overload

toán tử = và viết copy constructor cũng sử dụng lại cách này, mà không phải dùng đến prototype template function

CODE #include <iostream> #include <string> using namespace std; template<typename T> class Array { public: int size; T* elems; Array(int); Array(const Array<T>*&); void setValue(const T&,int i); T& getValue(int n);

Array<T>& operator=(const Array<T>*&);

friend bool operator!=(const Array<T>&,const Array<T>&); };

template<typename T> Array<T>::Array(int size) {

elems = new T[size]; }

template<typename T>

void Array<T>::setValue(const T& value,int i) {

*(elems+i) = value; }

T& Array<T>::getValue(int i) { return *(elems+i); } template<typename T> Array<T>::Array(const Array<T>*& src) { size=src.size;

elems = new T[size]; for(int i=0;i<size;i++)

*(elems+i) = *(src.elems+i); }

template<typename T>

Array<T>& Array<T>::operator=(const Array<T>*& src) {

if(*this!=src) //to avoid self-assignment {

size=src.size;

elems = new T[size]; for(int i=0;i<size;i++) *(elems+i) = *(src.elems+i); } return *this; } template<typename T>

bool operator!=(const Array<T>& a1,const Array<T>& a2) {

if(a1.size!=a2.size) return true; else for(int i=0;i<a1.size;i++)

return true; } int main() { Array<string> a(2); a.setValue("hello",0); a.setValue("world",1); Array<string> b(3); b = a; cout<<b.getValue(0)<<endl; cout<<b.getValue(1)<<endl; return 0; }

LẬP TRÌNH C/C++ NÂNG CAO

Một phần của tài liệu LẬP TRÌNH C/C++ NÂNG CAO potx (Trang 30 - 41)

Tải bản đầy đủ (PDF)

(111 trang)