<< Chapter < Page Chapter >> Page >

cout<<MyAbs(-2)<<endl;

cout<<MyAbs(3.5)<<endl;

Trong lần gọi thứ nhất, hàm MyAbs() có tham số thực là int nên trình biên dịch tạo ra hàm int MyAbs(int) theo dạng của hàm template, lần thứ hai sẽ tạo ra hàm float MyAbs(float).

Mỗi tham số hình thức trong một định nghĩa hàm template phải xuất hiện trong danh sách tham số của hàm tối thiểu một lần. Tên của tham số hình thức chỉ có thể sử dụng một lần trong danh sách tham số của phần đầu template.

Ví dụ 9.1: Sử dụng hàm template để in các giá trị của một mảng có kiểu bất kỳ.

1: //Chương trình 9.1

2: #include<iostream.h>

3:

4: template<class T>

5: void PrintArray(T *Array, const int Count)

6: {

7: for (int I = 0; I<Count; I++)

8: cout<<Array[I]<<" ";

9:

10: cout<<endl;

11: }

12:

13: int main()

14: {

15: const int Count1 = 5, Count2 = 7, Count3 = 6;

16: int A1[Count1] = {1, 2, 3, 4, 5};

17: float A2[Count2] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7};

18: char A3[Count3] = "HELLO";

19: cout<<"Array A1 contains:"<<endl;

20: PrintArray(A1, Count1); //Hàm template kiểu int

21: cout<<"Array A2 contains:"<<endl;

22: PrintArray(A2, Count2); //Hàm template kiểu float

23: cout<<"Array A3 contains:"<<endl;

24: PrintArray(A3, Count3); //Hàm template kiểu char

25: return 0;

26: }

Chúng ta chạy ví dụ 9.1 , kết quả ở hình 9.1

Hình 9.1: Kết quả của ví dụ 9.1

Ví dụ 9.2: Hàm template có thể có nhiều tham số.

1: //Chương trình 9.2

2: #include<iostream.h>

3:

4: template<class T>

5: T Max(T a, T b)

6: {

7: return (a>b)?a:b;

8: }

9:

10: int main()

11: {

12: float A,B;

13: cout<<"Enter first number:";

14: cin>>A;

15: cout<<"Enter second number:";

16: cin>>B;

17: cout<<"Maximum:"<<Max(A,B);

18: return 0;

19: }

Chúng ta chạy ví dụ 9.2 , kết quả ở hình 9.2

Hình 9.2: Kết quả của ví dụ 9.2

Một hàm template có thể được đa năng hóa theo vài cách. Chúng ta có thể cung cấp các hàm template khác mà mô tả cùng tên hàm nhưng các tham số hàm khác nhau. Một hàm template cũng có thể được đa năng hóa bởi cung cấp hàm non-template với cùng tên hàm nhưng các tham số hàm khác nhau. Trình biên dịch thực hiện một xử lý so sánh để xác định hàm gọi khi một hàm được gọi. Đầu tiên trình biên dịch cố gắng tìm và sử dụng một đối sánh chính xác mà các tên hàm và các kiểu tham số đối sánh chính xác. Nếu điều này thất bại, trình biên dịch kiểm tra nếu một hàm template đã có mà có thể phát sinh một hàm template với một đối sánh chính xác của tên hàm và các kiểu tham số. Nếu một hàm template như thế được tìm thấy, trình biên dịch phát sinh và sử dụng hàm template thích hợp. Chú ý xử lý đối sánh này với các template đòi yêu các đối sánh chính xác trên tất cả kiểu tham số-không có các chuyển đổi tự động được áp dụng.

Các lớp template

Bên cạnh hàm template, ngôn ngữ C++ còn trang bị thêm lớp template, lớp này cũng mang đầy đủ ý tưởng của hàm template. Các lớp template được gọi là các kiểu có tham số (parameterized types) bởi vì chúng đòi hỏi một hoặc nhiều tham số để mô tả làm thế nào tùy chỉnh một lớp template chung để tạo thành một lớp template cụ thể.

Chúng ta cài đặt một lớp Stack, thông thường chúng ta phải định nghĩa trước một kiểu dữ liệu cho từng phần tử của stack. Nhưng điều này chỉ mang lại sự trong sáng cho một chương trình và không giải quyết được vấn đề tổng quát. Do đó chúng ta định nghĩa lớp template Stack.

Ví dụ 9.3:

File TSTACK.H:

1: //TSTACK.H

2: //Lớp template Stack

3: #ifndef TSTACK_H

4: #define TSTACK_H

5:

6: #include<iostream.h>

7:

8: template<class T>

9: class Stack

10: {

11: private:

12: int Size; //Kích thước stack

13: int Top;

14: T *StackPtr;

15: public:

16: Stack(int = 10);

17: ~Stack()

18: {

19: delete [] StackPtr;

20: }

21: int Push(const T&);

22: int Pop(T&);

23: int IsEmpty() const

24: {

25: return Top == -1;

26: }

27: int IsFull() const

28: {

29: return Top == Size - 1;

30: }

31: };

32:

33: template<class T>

34: Stack<T>::Stack(int S)

35: {

36: Size = (S>0&&S<1000) ? S : 10;

37: Top = -1;

38: StackPtr = new T[Size];

39: }

40:

41: template<class T>

42: int Stack<T>::Push(const T&Item)

43: {

44: if (!IsFull())

45: {

46: StackPtr[++Top] = Item;

47: return 1;

48: }

49: return 0;

50: }

51:

52: template<class T>

53: int Stack<T>::Pop(T&PopValue)

54: {

55: if (!IsEmpty())

56: {

57: PopValue = StackPtr[Top--];

58: return 1;

59: }

60: return 0;

61: }

62:

63: #endif

File CT9_3.CPP:

1: //CT9_3.CPP

2: //Chương trình 9.3

3: #include "tstack.h"

4:

5: int main()

6: {

7: Stack<float>FloatStack(5);

8: float F = 1.1;

9: cout<<"Pushing elements onto FloatStack"<<endl;

10: while (FloatStack.Push(F))

11: {

12: cout<<F<<' ';

13: F += 1.1;

14: }

15:cout<<endl<<"Stack is full. Cannot push "<<F<<endl

16:   <<endl<<"Popping elements from FloatStack"<<endl;

17: while (FloatStack.Pop(F))

18: cout<<F<<' ';

19: cout<<endl<<"Stack is empty. Cannot pop"<<endl;

20: Stack<int>IntStack;

21: int I = 1;

22: cout<<endl<<"Pushing elements onto IntStack"<<endl;

23: while (IntStack.Push(I))

24: {

25: cout<<I<<' ';

26: ++I ;

27: }

28:cout<<endl<<"Stack is full. Cannot push "<<I<<endl

29: <<endl<<"Popping elements from IntStack"<<endl;

30: while (IntStack.Pop(I))

31: cout<<I<<' ';

32: cout<<endl<<"Stack is empty. Cannot pop"<<endl;

33: return 0;

34: }

Chúng ta chạy ví dụ 9.3 , kết quả ở hình 9.3

Hình 9.3: Kết quả của ví dụ 9.3

Hàm thành viên định nghĩa bên ngoài lớp template bắt đầu với phần đầu là

template<class T>

Sau đó mỗi định nghĩa tương tự một định nghĩa hàm thường ngoại trừ kiểu phần tử luôn luôn được liệt kê tổng quát như tham số kiểu T. Chẳng hạn:

template<class T>

int Stack<T>::Push(const T&Item)

{

…………….

}

Ngôn ngữ C++ còn cho phép chúng ta tạo ra các lớp template linh động hơn bằng cách cho phép thay đổi giá trị của các thành viên dữ liệu bên trong lớp. Khi đó lớp có dạng của một hàm với tham số hình thức.

Bài tập

Bài 1: Viết hàm template trả về giá trị trung bình của một mảng, các tham số hình thức của hàm này là tên mảng và kích thước mảng.

Bài 2: Cài đặt hàng đợi template.

Bài 3: Cài đặt lớp template dùng cho cây nhị phân tìm kiếm (BST).

Bài 4: Cài đặt lớp template cho vector để quản lý vector các thành phần có kiểu bất kỳ.

Bài 5: Viết hàm template để sắp xếp kiểu dữ liệu bất kỳ.

Bài 6: Trong C++, phép toán new được dùng để cấp phát bộ nhớ, khi không cấp phát được con trỏ có giá trị NULL. Hãy cài đặt lại các lớp Matrix và Vector trong đó có bổ sung thêm thành viên là lớp exception với tên gọi là Memory để kiểm tra việc cấp phát này.

Get Jobilize Job Search Mobile App in your pocket Now!

Get it on Google Play Download on the App Store Now




Source:  OpenStax, Lập trình hướng đối tượng. OpenStax CNX. Jul 29, 2009 Download for free at http://cnx.org/content/col10794/1.1
Google Play and the Google Play logo are trademarks of Google Inc.

Notification Switch

Would you like to follow the 'Lập trình hướng đối tượng' conversation and receive update notifications?

Ask