khuôn hình lớp một lần rồi sau đó có thể áp dụng chúng với các kiểu dữ liệu khác nhau để được các lớp thể hiện khác nhau.
4.2.2. Tạo một khuôn hình lớp
Xét ví dụ 4.8:
#include<iostream.h>
#include<conio.h> class stack
{
private:
unsigned int max; unsigned int top; int *a;
Có thể bạn quan tâm!
- Quy Tắc Gán Địa Chỉ Đối Tượng Cho Con Trỏ Lớp Cơ Sở
- Lập trình hướng đối tượng - 18
- Các Tham Số Kiểu Cđa Khuôn Hình Hàm
- Sự Giống Nhau Cđa Các Lớp Thể Hiện
- Lập trình hướng đối tượng - 22
- Lập trình hướng đối tượng - 23
Xem toàn bộ 256 trang tài liệu này.
public:
stack();
~stack();
void push(int x); int full();
int empty(); int pop();
};
stack::stack()
{
top=0;
cout<<"Kich thuoc stack:";cin>>max; a = new int[max];
}
stack::~stack()
{
top = 0;
max = 0; delete a;
}
int stack::empty()
{
if(top<=0) return 1;
else return 0;
}
int stack::full()
{
if(top>=max) return 1;
else return 0;
}
void stack::push(int x)
{
if(full())
{
cout<<"stack day"; return;
}
top=top+1; a[top]=x;
}
int stack::pop()
{
if(empty())
{
cout<<"Stack rong"; return 0;
}
top=top-1; return a[top+1];
}
void main()
{
stack s; int n;
cout<<"n=";cin>>n; while(n>0)
{
s.push(n % 2); n = n / 2;
}
while(!s.empty()) cout<<s.pop(); getch();
}
Trên đây là ví dụ về xây dựng lớp stack cài đặt kiểu kề tiếp chứa các phần tử là các số nguyên kiểu int. Lớp stack có một hàm tạo (stack), các phương thức: bổ sung phần tử (push), loại bỏ phần tử (pop), kiểm tra stack đầy (full), kiểm tra stack rỗng (empty). Tuy nhiên, lớp stack trên chỉ làm việc được với các số kiểu int, nếu ta muốn làm việc với các phần tử không phải kiểu int chẳng hạn kiểu float, double, char, hay kiểu student, ...thì ta lại phải xây dựng các lớp khác chỉ với việc thay đổi kiểu dữ liệu cđa thuộc tính a, còn về thuật toán thì không có gì thay đổi. Để tránh sự trùng lặp trong các tình huống như trên, chương trình dịch C++ cho phép định nghĩa một khuôn hình lớp và sau đó áp dụng khuôn hình lớp này với các kiểu dữ liệu khác nhau để thu được các lớp thể hiện như mong muốn.
Cú pháp cđa khuôn hình lớp như sau: template <class T1, class T2, .., class Tn> class tên_lớp
{
//khai báo các thuộc tính có kiểu: T1, T2,.., Tn
//khai báo các phương thức cđa lớp
};
Cũng giống như các khuôn hình hàm, cú pháp template <class T1, class T2,
.., class Tn> xác định rằng đó là một khuôn hình trong đó có các tham số kiểu T1, T2, ..., Tn .
Khi các phương thức được khai bên trong định nghĩa ta sẽ viết như bình thương, còn đối với các phương thức viết ngoài định nghĩa lớp ta phải nhắc lại các tham số kiểu cđa khuôn hình lớp, có nghĩa là phải nhắc lại template <class
T1, class T2, .., class Tn>trước định nghĩa hàm, còn tên cđa khuôn hình lớp được viết như là tên_lớp<T1, T2,.., Tn>
Bây giờ ta sẽ xây dựng khuôn hình lớp stack để có thể làm việc với các kiểu phần tử khác nhau (Trong một stack thì các phần tử có cùng một kiểu dữ liệu)
Ví dụ 4.9:
#include<iostream.h>
#include<conio.h> template <class t> class stack
{
private:
unsigned int max; unsigned int top; t *a;
public:
stack();
~stack();
void push(t x); int full();
int empty(); t pop();
};
template <class t>stack<t>::stack()
{
top=0;
cout<<"Kich thuoc stack:";cin>>max; a = new t[max];
}
template <class t> stack<t>::~stack()
{
top=0; max=0; delete a;
}
template <class t>int stack<t>::empty()
{
if(top<=0) return 1;
else return 0;
}
template <class t>int stack<t>::full()
{
if(top>=max) return 1;
else return 0;
}
template <class t>void stack<t>::push(t x)
{
if(full())
{
cout<<"stack day"; return;
}
top=top+1; a[top]=x;
}
template <class t>t stack<t>::pop()
{
if(empty())
{
cout<<"Stack rong"; return 0;
}
top=top-1; return a[top+1];
}
void main()
{
stack<int> s;//sử dụng khuôn hình lớp stack int n;
cout<<"n=";cin>>n; while(n>0)
{
s.push(n % 2); n = n / 2;
}
while(!s.empty()) cout<<s.pop(); getch();
}
4.2.3. Sử dụng khuôn hình lớp
Sau khi khai báo khuôn hình cđa lớp ta có thể dùng khuôn hình lớp đó để khai báo đối tượng, mảng đối tượng, con trỏ đối tượng bằng cách chỉ rõ kiểu dữ liệu cho các tham số kiểu được sử dụng trong khuôn hình theo cú pháp:
tên_lớp<kiểu dữ liệu1, kiểu dữ liệu 2,.., kiểu dữ liệu n> Tên_đối_tượng;
ứng với mỗi kiểu dữ liệu cụ thể cđa một tham số kiểu cho ta một thể hiện cđa khuôn hình lớp. Ví dụ ta có thể có các kiểu thể hiện khác nhau cđa khuôn hình lớp stack khi khai báo các đối tượng như sau:
stack<float> s1; stack<char> s2; stack<*int> s3;
4.2.4. Các tham số trong khuôn hình lớp
Hoàn toàn giống nh− khuôn hình hàm, các khuôn hình lớp có thể có các tham số kiểu vàtham số biểu thức. Tuy có nhiều điểm giống nhau giữa khuôn hình hàm vàkhuôn hình lớp, nh− ng các ràng buộc đối với các kiểu tham số lại không nh− nhau.
Xét ví dụ 4.10:
template <class T, class U, class V> //danh sách ba tham số kiểu class try
{
T x;
U t[5];
...
V fm1 (int, U);
...
};
Để sản sinh ra một lớp thể hiện ta liệt kê đằng sau tên khuôn hình lớp các tham số thực (làtên các kiểu dữ liệu) với số l− ợng bằng với số các tham số trong danh sách (template<...>) cđa khuôn hình lớp. Ví dụ để sinh ra các lớp thể hiện cđa khuôn hình lớp try ta viết như sau:
try <int, float, int> // lớp thể hiện với ba tham số int, float, int hoặc
try <int,int *, double>// lớp thể hiện với ba tham số int, int *, double hay
try <char *, int, obj> // lớp thể hiện với ba tham số char *, int, obj
Trong dòng cuối ta cuối giả định obj làmột kiểu dữ liệu đã đ− ợc định nghĩa tr− ớc đó. Thậm chí có thể sử dụng các lớp thể hiện để làm tham số thực cho các lớp thể hiện khác, chẳng hạn:
try <float, point<int>, double>
try <point<int>,point<float>, char *>
Ta thấy rằng, vấn đề t− ơng ứng chính xác đ− ợc nói tới trong các khuôn hình hàm không còn hiệu lực với các khuôn hình lớp. Với các khuôn hình hàm, việc sản sinh một thể hiện không chỉ dựa vào danh sách các tham số có trong template<...> màcòn dựa vào danh sách các tham số hình thức trong tiêu đề cđa hàm. Một tham số hình thức cđa một khuôn hình hàm có thể có kiểu, làmột lớp thể hiện nào đó, chẳng hạn:
template <class T> void fct(point<T>)
{... }
Việc khởi tạo mới các kiểu dữ liệu mới vẫn áp dụng đ− ợc trong các khuôn hình lớp. Một khuôn hình lớp có thể có các thành phần(dữ liệu hoặc hàm) static. Trong
tr− ờng hợp này, cần phải biết rằng, mỗi thể hiện cđa lớp có một tập hợp các thành phần static cđa riêng mình:
4.2.5. Các tham số biểu thức trong khuôn hình lớp
Một khuôn hình lớp có thể chứa các tham số biểu thức. So với khuôn hình hàm, khái niệm tham số biểu thức trong khuôn hình lớp có một số điểm khác biệt: tham số thực tế t− ơng ứng với tham số biểu thức phải làmột hằng số.
Giả sử rằng ta muốn định nghĩa một lớp array để thao tác trên các mảng một chiều chứa các đối t− ợng có kiểu bất kỳ. Một cách tự nhiên ta nghĩ ngay đến việc tạo một khuôn hình lớp với một tham số kiểu. Đồng thời còn có thể dùng một tham số thứ hai để xác định số thành phần cđa mảng. Trong tr− ờng hợp này, định nghĩa cđa khuôn hình
lớp có dạng nh− sau:
template <class T, int n> class array
{
T tab[n]; public:
...
};
Danh sách các tham số (template<...>) chứa hai tham số với đặc điểm khác nhau hoàn toàn: một tham số kiểu đ− ợc xác đinh bởi từ khoá class, một tham số biểu thức kiểu int>. Chúng ta sẽ phải chỉ rõ giá trị cđa chúng trong khai báo các lớp thể hiện. Chẳng hạn, lớp thể hiện:
array <int ,4>
t− ơng ứng với khai báo nh− sau: class array<int,4>
{
int tab[4]; public:
...
};
Sau đây làmột ví dụ hoàn chỉnh: Ví dụ 4.11:
#include <iostream.h>
#include <conio.h>
template <class T, int n> class array