Bài giảng Ngôn ngữ lập trình - Bài 7: Khuôn mẫu (Template) và thư viện chuẩn (STL) - Lê Nguyễn Tuấn Thành
Tóm tắt Bài giảng Ngôn ngữ lập trình - Bài 7: Khuôn mẫu (Template) và thư viện chuẩn (STL) - Lê Nguyễn Tuấn Thành: ... để kiểm tra kích thước  Do đó tham số kích thước có thể không cần nếu hàm không thay đổi tham số c-string  Sử dung “const” để bảo vệ những đối số c-string không bị thay đổi 19 I/O VỚI C-STRING  Xuất dữ liệu với toán tử chèn: <<  Do toán tử << đã được nạp chồng cho c-...e; cout << "Enter input: "; getline(cin, line, "?"); // nhập vào các ký tự cho đến khi gặp “?” 32 CÂU HỎI  int n; string line; cin >> n; getline(cin, line);  Nếu nhập vào 42 Hello hitchhiker.  Hai biến n và line có giá trị là gì?  Biến n được gán giá trị...n mẫu hàm không sử dụng bộ nhớ  Mã thực sự chỉ được tạo khi tên khuôn mẫu được gọi  Khi truyền một đối tượng của lớp cho một khuôn mẫu hàm, phải đảm bảo rằng mọi toán tử được chỉ định trong khuôn mẫu đã được định nghĩa hoặc nạp chồng trong định nghĩa của lớp  Mọi kiểu dữ liệu chỉ đị...
NGÔN NGỮ LẬP TRÌNH 
Bài 7: 
Khuôn mẫu (Template) và 
Thư viện chuẩn (STL) 
Giảng viên: Lê Nguyễn Tuấn Thành 
Email: thanhlnt@tlu.edu.vn 
Bộ Môn Công Nghệ Phần Mềm – Khoa CNTT 
Trường Đại Học Thủy Lợi 
NỘI DUNG 
1. Nhắc lại về vector 
2. C-string và lớp String 
3. Khuôn mẫu hàm 
4. Khuôn mẫu lớp 
2 
Bài giảng có sử dụng hình vẽ trong cuốn sách “Practical Debugging in C++, 
A. Ford and T. Teorey, Prentice Hall, 2002” 
1. NHẮC LẠI VỀ VECTOR 
MỘT KHUÔN MẪU LỚP (CLASS TEMPLATE) 
CƠ BẢN VỀ VECTOR 
 Dùng để lưu trữ tập dữ liệu CÙNG KiỂU, giống 
mảng, 
 Nhưng vector có thể phình to hoặc thu nhỏ kích 
thước trong lúc chạy chương trình (không giống 
như mảng có kích thước cố định) 
 Thư viện: #include 
 Ví dụ khai báo 
 vector vIA; // Khai báo một vector chứa 
dữ liệu kiểu int 
 vector vIB (10); // Khai báo một vector có 
kích thước ban đầu là 10, chứa dữ liệu kiểu int 
 vector vIC (10, 2); // Khai báo một vector có 
kích thước ban đầu là 10, chứa dữ liệu kiểu int và dữ 
liệu được khởi tạo giá trị 2 
4 
MỘT SỐ HÀM THÀNH VIÊN CỦA VECTOR 
Phương thức Mục đích 
v.assign(n,e) Gán tập giá trị mới cho vector, thay thế nội 
dung hiện tại của nó đồng thời thay đổi kích 
thước 
v[i] hoặc v.at[i] Tham chiếu đến phần tử thứ i của vector 
v.clear() Làm rỗng vector 
v.pop_back() Xóa phần tử cuối cùng của vector 
v.push_back(e) Thêm phần tử e vào cuối của vector 
v.resize(new_size) Thay đổi kích thước của vector 
5 
Danh sách đầy đủ có thểm xem tại đây 
SỬ DỤNG ITERATOR 
 Trong lập trình hướng đối tượng (OOP), một 
iterator là một đối tượng cho phép lập trình viên 
duyệt qua (traverse) các phần tử trong một 
container, như danh sách (list), mảng, vector  
6 
2. C-STRING VÀ LỚP STRING 
MỤC TIÊU 
 C-Strings: một kiểu mảng cho chuỗi ký tự 
 Các công cụ thao tác ký tự (char) 
 Character I/O 
 Hàm thành viên get, put 
 Một số hàm khác: pushback, peek, ignore  
 Lớp String chuẩn 
 Xử lý chuỗi ký tự với lớp String 
8 
HAI CÁCH BIỂU DIỄN CHUỖI (STRING) 
 C-strings 
 Một mảng với các phần tử có kiểu cơ sở char 
 Chuỗi được kết thúc với kí tự null, “\0” 
 Là phương thức cũ được kế thừa từ C 
 Lớp String 
 Sử dụng khuôn mẫu (template) 
9 
C-STRINGS 
 Một mảng các phần tử với kiểu cơ sở char 
 Mỗi phần tử của mảng là một ký tự 
 Ký tự mở rộng “\0” 
 Được gọi là ký tự rỗng (null character) 
 Là dấu hiệu kết thúc một chuỗi ký tự 
 Chúng ta đã sử dụng C-strings! 
 Ví dụ: literal “Hello” được lưu trữ như một c-string 
10 
BIẾN C-STRING 
 Khai báo: char s[10] 
 Khai báo một biến c-string để lưu trữ 9 ký tự 
 Và kí tự thứ 10 là ký tự null (“\0”) 
 Chỉ có một điểm khác với mảng chuẩn: 
 C-strings phải chứa ký tự null ! 
 Khởi tạo một c-string: char s[10] = “Hi Mom!” 
 Không cần thiết phải điền đầy đủ (kích thước) mảng 
 Đặt ký tự “\0” ở cuối 
 Có thể bỏ qua kích thước mảng: 
 char shortString[] = "abc"; 
11 
THAO TÁC VỚI C-STRING QUA CHỈ SỐ 
 Một c-string LÀ một mảng => có thể truy cập thành 
viên thông qua chỉ số (index) 
 Ví dụ: char ourString[5] = "Hi"; 
 ourString[0] là "H“ 
 ourString[1] là "i“ 
 ourString[2] là "\0“ 
 ourString[3] là không xác định (unknown) 
 ourString[4] là không xác định (unknown) 
 Chú ý: nếu thực hiện phép gán ourString[2] = “a”; 
 Ghi đè ký tự “\0” (null) bởi ký tự “a” 
 Nếu ký tự null bị ghi đè, c-string không còn hoạt động 
như c-string nữa! => kết quả không dự đoán được 
12 
TOÁN TỬ = VÀ == VỚI C-STRINGS 
 C-strings không giống những biến khác 
 Không thể sử dụng phép gán hoặc so sánh 
 Chỉ có thể sử dụng toán tử “=” lúc khởi tạo một c-
string! 
char aString[10]; 
aString = “Hello”; // KHÔNG HỢP LỆ 
 Phải sử dụng hàm thư viện cho phép gán: 
strcpy(aString, "Hello"); 
 Một hàm được xây dựng sẵn trong 
 Đặt giá trị của aString bằng với “Hello” 
 KHÔNG kiểm tra kích thước! 
13 
SO SÁNH C-STRINGS 
 Không thể sử dụng toán tử “==” để so sánh c-strings 
 char aString[10] = “Hello”; 
 char anotherString[10] = “Goodbye”; 
 aString == anotherString; // KHÔNG hợp lệ 
 Phải sử dụng thư viện hàm: 
 if (strcmp(aString, anotherString)) 
 cout << "Strings NOT same."; 
else 
 cout << "Strings are same."; 
14 
DANH SÁCH HÀM THAO TÁC CHUỖI 
TRONG (1/2) 
15 
DANH SÁCH HÀM THAO TÁC CHUỖI 
TRONG (2/2) 
16 
HÀM STRLEN() 
 “STRing LENgth” – độ dài của chuỗi 
 Trả về số lượng ký tự 
 Không bao gồm ký tự null 
 Ví dụ: 
 char myString[10] = "dobedo"; 
cout << strlen(myString); 
 Giá trị trả về: 6 
17 
HÀM STRCAT() 
 “STRing ConcATnate” 
 Dùng để nối chuỗi 
 char stringVar[20] = "The rain"; 
strcat(stringVar, " in Spain"); 
 Kết quả: stringVar bây giờ là "The rain in Spain " 
18 
ĐỐI SỐ VÀ THAM SỐ C-STRING 
 Nhớ lại: c-string là một mảng 
 Vì vậy có thể dùng c-string làm tham số mảng 
 c-string được truyền vào hàm có thể bị thay đổi bởi 
hàm tiếp nhận! 
 Giống như mảng, thông thường cũng truyền cả 
kích thước của c-string vào hàm 
 Hàm cũng “có thể” sử dụng kí tự “\0” để kiểm tra kích 
thước 
 Do đó tham số kích thước có thể không cần nếu hàm 
không thay đổi tham số c-string 
 Sử dung “const” để bảo vệ những đối số c-string không 
bị thay đổi 19 
I/O VỚI C-STRING 
 Xuất dữ liệu với toán tử chèn: << 
 Do toán tử << đã được nạp chồng cho c-strings! 
 Nhập dữ liệu với toán tử: >> 
 Chú ý khi nhập dữ liệu: khoảng trắng 
(whitespace) được dùng để phân cách (delimiter) 
 Tab, space, ngắt dòng (line breaks) bị bỏ qua 
 Dữ liệu đọc vào sẽ dừng ghi bắt gặp delimiter 
 Phải ước lượng kích thước c-string đủ lớn để chứa 
toàn bộ chuỗi, C++ không đưa ra bất kỳ cảnh bảo 
nào cho các tình huống vượt kích thước! 
20 
VÍ DỤ 
NHẬP DỮ LIỆU CHO C-STRING DÙNG CIN 
 char a[80], b[80]; 
cout << "Enter input: "; 
cin >> a >> b; 
cout << a << b << "END OF OUTPUT\n"; 
Nhập vào: Do be do to you! 
Kết quả in ra màn hình: DobeEND OF OUTPUT 
C-string a nhận giá trị “do” 
C-string b nhận giá trị “be” 
21 
NHẬP DỮ LIỆU CHO C-STRING 
DÙNG HÀM GETLINE 
 Có thể nhận vào cả một dòng cho c-string sử dụng 
hàm định nghĩa sẵn getline() 
 char a[80]; 
cout << "Enter input: "; 
cin.getline(a, 80); // chiều dài chuỗi muốn nhập vào là 79? 
cout << a << "END OF OUTPUT\n"; 
Nhập vào: Do be do to you! 
Kết quả in ra màn hình: 
Do be do to you! END OF OUTPUT 
22 
HÀM THÀNH VIÊN GET() 
 Đọc một ký tự một lần 
 Là hàm thành viên của đối tượng cin 
 char nextSymbol; 
cin.get(nextSymbol); 
 Đọc ký tự tiếp theo và gán cho biến nextSymbol 
 Đối số phải là kiểu char, không phải chuỗi ! 
23 
HÀM THÀNH VIÊN PUT() 
 Hiển thị một ký tự một lần 
 Là hàm thành viên của đối tượng cout 
 Ví dụ: 
 cout.put("a"); // output kí tự “a” ra màn hình 
 char myString[10] = "Hello"; 
cout.put(myString[1]); // Hiển thị ký tự “e” ra 
màn hình 
24 
MỘT VÀI HÀM THÀNH VIÊN KHÁC 
 putback() 
 Giảm vị trí hiện tại trong stream lùi về một ký tự 
 cin.putback(lastChar); 
 peek() 
 Trả về ký tự tiếp theo, nhưng không loại bỏ nó khỏi 
luồng input 
 peekChar = cin.peek(); 
 ignore() 
 Bỏ qua input, cho đến khi gặp ký tự được chỉ định 
 cin.ignore(1000, "\n"); // bỏ qua nhiều nhất 1000 kí tự 
cho đến khi gặp “\n” 
25 
DANH SÁCH HÀM THAO TÁC KÝ TỰ 
TRONG THƯ VIỆN (1/3) 
26 
DANH SÁCH HÀM THAO TÁC KÝ TỰ 
TRONG THƯ VIỆN (2/3) 
27 
DANH SÁCH HÀM THAO TÁC KÝ TỰ 
TRONG THƯ VIỆN (3/3) 
28 
LỚP STRING CHUẨN 
 Được định nghĩa trong thư viện 
 #include 
using namespace std; 
 Biến string và các biểu thức được xử lý giống như 
những kiểu đơn giản khác 
 Có thể gán, so sánh, cộng 
 string s1, s2, s3; 
s3 = s1 + s2; //Concatenation 
s3 = "Hello Mom!" //Assignment 
 Lưu ý: c-string “Hello Mom!” được tự động chuyển 
thành kiểu string! 
29 
CHƯƠNG TRÌNH VỚI LỚP STRING 
30 
I/O VỚI LỚP STRING 
 Giống như những kiểu khác! 
 string s1, s2; 
cin >> s1; 
cin >> s2; 
Nhập vào: 
May the hair on your toes grow long and curly! 
s1 nhận giá trị “May” 
s2 nhận giá trị “the” 
 Bỏ qua các khoảng trắng (whitespace) 
31 
HÀM GETLINE() VỚI LỚP STRING 
 string line; 
cout << "Enter a line of input: "; 
getline(cin, line); 
cout << line << "END OF OUTPUT"; 
Nhập vào: Do be do to you! 
Kết quả in ra màn hình: 
Do be do to you! END OF OUTPUT 
 string line; 
cout << "Enter input: "; 
getline(cin, line, "?"); // nhập vào các ký tự cho đến 
khi gặp “?” 
32 
CÂU HỎI 
 int n; 
string line; 
cin >> n; 
getline(cin, line); 
 Nếu nhập vào 
 42 
 Hello hitchhiker. 
 Hai biến n và line có giá trị là gì? 
 Biến n được gán giá trị 42 
 Biến line được một chuỗi rỗng 
 Tại sao? 
 cin >> n bỏ qua leading whitespace, để lại ký tự “\n” 
trên stream cho hàm getline()! 33 
HÀM XỬ LÝ CỦA LỚP STRING 
 Có một số hàm giống như c-strings 
 Và còn nhiều hơn! 
 Trên 100 hàm thành viên của lớp string chuẩn 
 Một vài hàm thành viên 
 .length(): trả về chiều dài của biến string 
 .at(i): trả về tham chiếu tới ký tự ở vị trí i 
34 
DANH SÁCH HÀM THÀNH VIÊN 
CỦA LỚP STRING (1/2) 
35 
DANH SÁCH HÀM THÀNH VIÊN 
CỦA LỚP STRING (2/2) 
36 
CHUYỂN ĐỐI GIỮA C-STRING VÀ 
ĐỐI TƯỢNG CỦA LỚP STRING 
 Tự động chuyển kiểu 
 Từ c-string thành đối tượng của lớp string 
 char aCString[] = "My C-string"; 
string stringVar; 
stringVar = aCstring; // Hợp lệ! 
 Nhưng không thể viết 
aCString = stringVar; // KHÔNG hợp lệ! 
 Không thể tự động chuyển từ đối tượng của lớp string 
sang c-string 
 Phải sử dụng chuyển tường minh bằng hàm strcpy 
strcpy(aCString, stringVar.c_str()); 
37 
TÓM TẮT C-STRING VÀ LỚP STRING 
 Biến c-string là một mảng các ký tự 
 Cộng thêm ký tự null, “\0” 
 C-strings hoạt động giống như mảng 
 Không thể gán, so sánh giống như những biến đơn 
giản 
 Các thư viện và chứa nhiều 
hàm thao tác hữu ích 
 cin.get() đọc ký tự đơn tiếp theo 
 getline() cho phép đọc toàn dòng 
 Đối tượng của lớp string thao tác tốt hơn c-strings 
38 
3. KHUÔN MẪU 
Templates 
MỤC TIÊU 
Khuôn mẫu hàm (Function Templates) 
Khuôn mẫu lớp (Class Templates) 
Khuôn mẫu và Kế thừa 
Thư viện khuôn mẫu chuẩn (STL) 
40 
KHUÔN MẪU HÀM 
 Một mô hình (một mẫu) giúp tạo định nghĩa của 
những hàm chỉ khác nhau về kiểu dữ liệu mà 
chúng thao tác. 
 Đây là một hàm chung cho những hàm đó 
 Thích hợp cho những hàm thực thi cùng một tác vụ 
nhưng với những tham số khác nhau 
 Khuôn mẫu hàm tốt hơn so với nạp chồng hàm 
bởi vì đoạn mã định nghĩa thao tác trong hàm chỉ 
cần được viết MỘT LẦN 
41 
VÍ DỤ VỀ KHUÔN MẪU HÀM (1/2) 
 Giả sử chúng ta có hai hàm sau với mục đích hoán 
vị giá trị của hai biến 
 Hai hàm này chỉ khác nhau về kiểu dữ liệu tham 
số (kiểu int và char) 
void swap(int &x, int &y) 
 { int temp = x; x = y; 
 y = temp; 
 } 
void swap(char &x, char &y) 
 { char temp = x; x = y; 
 y = temp; 
 } 
42 
VÍ DỤ VỀ KHUÔN MẪU HÀM (2/2) 
 Hai hàm này có thể được thay thế bởi MỘT khuôn 
mẫu hàm sau 
template 
void swap(T &x, T &y) 
 { T temp = x; x = y; 
 y = temp; 
 } 
43 
SỬ DỤNG KHUÔN MẪU HÀM 
 Khi gọi một khuôn mẫu hàm với một kiểu dữ liệu, 
trình biên dịch sẽ tạo một định nghĩa hàm thực sự 
từ khuôn mẫu này dựa theo kiểu dữ liệu của tham 
số 
 int i = 1, j = 2; 
 swap(i,j); 
 Đoạn mã trên sẽ khiến trình biên dịch khởi tạo 
khuôn mẫu hàm với kiểu dữ liệu int thay thế cho 
kiểu tham số T 
44 
BÀI TẬP CHO KHUÔN MẪU HÀM 
 Viết một khuôn mẫu hàm tìm kiếm một phần tử 
trong một mảng và in ra vị trí của phần tử đó 
trong mảng nếu tìm thấy, ngược lại in ra -1 
 template 
int search(const T a[], int numberUsed, T target) 
 {  } 
45 
MỘT VÀI LƯU Ý CHO KHUÔN MẪU HÀM 
 Khuôn mẫu hàm không sử dụng bộ nhớ 
 Mã thực sự chỉ được tạo khi tên khuôn mẫu được 
gọi 
 Khi truyền một đối tượng của lớp cho một khuôn 
mẫu hàm, phải đảm bảo rằng mọi toán tử được chỉ 
định trong khuôn mẫu đã được định nghĩa hoặc 
nạp chồng trong định nghĩa của lớp 
 Mọi kiểu dữ liệu chỉ định trong khuôn mẫu hàm 
phải được dùng bên trong thân của khuôn mẫu 
hàm 
 Lời gọi hàm phải truyền đầy đủ tham số (với kiểu 
dữ liệu) được chỉ định trong khuôn mẫu hàm 
 Khuôn mẫu hàm có thể được nạp chồng – với danh 
sách tham số khác nhau 
 Giống như các hàm thông thường, khuôn mẫu 
hàm phải được định nghĩa trước khi gọi 
46 
KHUÔN MẪU LỚP 
 Có thể định nghĩa khuôn mẫu cho lớp. Những lớp 
kiểu này định nghĩa những kiểu dữ liệu trừu 
tượng 
 Không giống như khuôn mẫu hàm, một khuôn 
mẫu lớp được khởi tạo bằng cách cung cấp cụ thể 
kiểu dữ liệu (ví dụ: int, float, string, ) khi định 
nghĩa đối tượng 
47 
VÍ DỤ VỀ KHUÔN MẪU LỚP (1/2) 
 Xem xét hai lớp sau 
 Một lớp để cộng hai số nguyên 
class Joiner 
{ 
 public: 
 int combine(int x, int y) 
 {return x + y;} 
}; 
 Một lớp để nối hai chuỗi 
class Joiner 
{ 
 public: 
 string combine(string x, string y) 
 {return x + y;} 
}; 
48 
VÍ DỤ VỀ KHUÔN MẪU LỚP (2/2) 
 Hai lớp trên có thể được thay thế bởi CHỈ một 
khuôn mẫu lớp sau 
template 
 class Joiner 
 { 
 public: 
 T combine(T x, T y) 
 {return x + y;} 
 }; 
49 
SỬ DỤNG KHUÔN MẪU LỚP 
 Joiner jd; 
 Joiner sd; 
 cout << jd.combine(3.0, 5.0); 
 cout << sd.combine("Hi ", "Ho"); 
Kết quả in ra màn hình: 8.0 và Hi Ho 
50 
BÀI TẬP KHUÔN MẪU LỚP 
 Cài đặt giao diện lớp sau 
51 
KHUÔN MẪU LỚP VÀ KẾ THỪA 
 Khuôn mẫu có thể được kết hợp với kế thừa 
 Chúng ta có thể: 
 Kế thừa một lớp thông thường từ một khuôn mẫu lớp 
 Kế thừa một khuôn mẫu lớp từ một khuôn mẫu lớp 
khác 
52 
THƯ VIỆN KHUÔN MẪU CHUẨN 
 STL – Standard Template Libray 
 Một thư viện bao gồm những khuôn mẫu được sử dụng 
thường xuyên cho cấu trúc dữ liệu và thuật toán 
(algorithms) 
 Chương trình có thể được phát triển nhanh hơn 
nếu chúng ta sử dụng những khuôn mẫu sẵn có 
này 
 Hai kiểu cấu trúc dữ liệu quan trọng trong STL 
 Bộ chứa (container): những lớp lưu trữ dữ liệu và 
 Bộ lặp (iterator): giống con trỏ, cung cấp cơ chế để 
truy cập các thành viên trong một container 
53 
BỘ CHỨA (CONTAINER) 
 Có hai kiểu bộ chứa (container) trong STL 
 Bộ chứa tuần tự (sequential containers): tổ chức và 
truy xuất dữ liệu một cách tuần tự, giống như kiểu 
mảng. Bao gồm: vector, dequeue và list 
 Bộ chứa liên kết (associative containers): sử dụng key 
để cho phép các phần tử có thể được truy cập một cách 
nhanh chóng. Bao gồm: set, multiset, map và 
multimap 
54 
TẠO ĐỐI TƯỢNG CONTAINER 
 Tạo một danh sách (list) của kiểu int 
 list mylist; 
 Tạo một vector của những đối tượng string: 
 vector myvector; 
55 
BỘ LẶP (ITERATOR) 
 Tổng quát hóa khái niệm con trỏ (pointer), được 
sử dụng để truy xuất thông tin trong bộ chứa 
(container) 
 Có nhiều loại lặp: 
 Lặp tiến (forward) : sử dụng toán tử ++ 
 Lặp hai chiều (bidirectional): sử dụng ++ và – 
 Truy cập ngẫu nhiên (random-access) 
 Input: có thể sử dụng với đối tượng cin và istream 
 Output: có thể sử dụng với đối tượng cout và ostream 
56 
CONTAINER VÀ ITERATOR 
 Mỗi lớp container định nghĩa: 
 Một kiểu iterator, sử dụng để truy xuất các thành viên 
của nó 
 Những hàm trả về iterator 
 begin(): đặt iterator vào phần tử đầu tiên 
 end(): đặt iterator vào phần tử cuối cùng 
 Iterator hỗ trợ các thao tác giống con trỏ (*iter, 
iter ++, iter --) 
 Kiểu của một iterator được quyết định bởi kiểu của 
container 
 list::iterator x; 
 list::iterator y; 57 
DUYỆT QUA MỘT CONTAINER 
 Xét một vector 
vector v; 
 for (int k=1; k<= 5; k++) 
 v.push_back(k*k); 
 Duyệt qua vector này sử dụng iterator 
vector::iterator iter = v.begin(); 
 while (iter != v.end()) 
 { cout << *iter << " "; iter++} 
Kết quả in ra màn hình: 1 4 9 16 25 
58 
GIẢI THUẬT 
 STL bao gồm một số giải thuật được cài đặt như 
những khuôn mẫu hàm thực thi trên các 
containers 
 Yêu cầu khai báo file tiêu đề “algorithm” 
(#include ) 
 Tập hợp các giải thuật bao gồm 
 binary_search 
 for_each 
 max_element, min_element 
 random_shuffle 
 find 
 sort 
  
59 
SỬ DỤNG GIẢI THUẬT TRONG STL 
 max_element(iter1, iter2): tìm phần tử lớn 
nhất trong một khoảng giới hạn bởi iter1 và iter2 
của container 
 min_element(iter1, iter2): tương tự với phần tử 
nhỏ nhất 
 random_shuffle(iter1, iter2): đảo ngẫu nhiên 
các giá trị trong khoảng giới hạn bởi iter1 và iter2 
 sort(iter1, iter2): sắp xếp theo giá trị tăng dần 
của khoảng giới hạn bởi iter1 và iter2 
60 
GIÁO TRÌNH THAM KHẢO 
 Giáo trình chính: W. Savitch, Absolute C++, 
Addison Wesley, 2002 
 Tham khảo: 
 A. Ford and T. Teorey, Practical Debugging in C++, 
Prentice Hall, 2002 
 Nguyễn Thanh Thủy, Kĩ thuật lập trình C++, NXB 
Khoa học và Kĩ Thuật, 2006 
61 
File đính kèm:
 bai_giang_ngon_ngu_lap_trinh_bai_7_khuon_mau_template_va_thu.pdf bai_giang_ngon_ngu_lap_trinh_bai_7_khuon_mau_template_va_thu.pdf




