Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP

 Các hàm (phương thức) truy vấn  Hàm khởi tạo sao chép (copy constructor)  Hàm với đối số ngầm định  Hàm tĩnh và dữ liệu tĩnh (static)  Hàm bạn – lớp bạn (friend)  Hàm đa năng (đa năng hóa hàm:overload)  Hàm chuyển đổi kiểu  Hàm tại chỗ (inline)

pdf53 trang | Chia sẻ: lylyngoc | Lượt xem: 1664 | Lượt tải: 2download
Bạn đang xem trước 20 trang tài liệu Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ĐH CÔNG NGHỆ THÔNG TIN Số tiết lý thuyết: 45 tiết Số tiết thực hành: 30 tiết 1 2 Chương 1: Tổng quan về OOP Chương 2: Lớp & đối tượng Chương 3: Hàm và hàm đa năng trong OOP Chương 4: Đa năng hóa toán tử Chương 5: Sự kế thừa và tính đa hình  Nội dung môn học: 3 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 4 Các hàm (phương thức) truy vấn  Khái niệm  Ví dụ  Phân loại  Đặc điểm  Khái niệm: Là các phương thức dùng để hỏi/gán giá trị cho các thành viên dữ liệu của một đối tượng.  Ví dụ:  Chương 3: Hàm và hàm đa năng trong OOP class Phanso{ private: int tuso,mauso; public: Phanso(); // Hàm khởi tạo không đối số Phanso(int,int); // Hàm khởi tạo hai đối số // Phương thức truy vấn int getTuso(){return tuso;} int getMauso(){return mauso;} void setTuso(int tu){tuso=tu;} void setMauso(int mau){mauso=mau;} }; 5 Các hàm (phương thức) truy vấn  Khái niệm  Ví dụ  Phân loại  Đặc điểm  Phân loại:  Truy vấn đơn giản (“giá trị của x là bao nhiêu?”)  Truy vấn điều kiện (“thành viên x có lớn hơn 10 không?”)  Truy vấn dẫn xuất (“tổng giá trị của các thành viên x và y là bao nhiêu?”)  Đặc điểm:  Phương thức dùng để bảo vệ các nguyên tắc đóng gói, đảm bảo việc đọc/ghi và kiểm tra giá trị cho các thành viên dữ liệu của lớp.  Phương thức này thường được quy ước đặt tên theo dạng tiền tố (get/set/is ứng với từng loại truy vấn),tiếp theo là tên của thành viên dữ liệu.  Chương 3: Hàm và hàm đa năng trong OOP 6 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 7 Hàm khởi tạo sao chép (copy constructor)  Khái niệm  Ví dụ  Cú pháp  Trường hợp sử dụng  Khái niệm: Là hàm khởi tạo có đối số là một đối tượng khác của cùng lớp đó. Ví dụ:  Cú pháp:  Chương 3: Hàm và hàm đa năng trong OOP void main(){ Phanso a; // khởi tạo không đối số Phanso b(2,3); // Hàm khởi tạo hai đối số Phanso c(b); // Hàm khởi tạo sao chép }; class X{ … public: X(); // Hàm khởi tạo không đối số X(const X&); // Hàm khởi tạo sao chép }; 8 Hàm khởi tạo sao chép (copy constructor)  Khái niệm  Ví dụ  Cú pháp  Trường hợp sử dụng  Trường hợp sử dụng:  Khi một đối tượng được khởi tạo từ một đối tượng khác của cùng lớp.  Khi một đối tượng được truyền như là một đối số cho hàm.  Khi hàm trả về một đối tượng.  Khi có cấp phát động thì hàm khởi tạo sao chép bắt buộc phải định nghĩa lại để tránh trường hợp con trỏ NULL (null pointer assignment).  Chương 3: Hàm và hàm đa năng trong OOP 9 Hàm khởi tạo sao chép (copy constructor)  Khái niệm  Ví dụ  Cú pháp  Trường hợp sử dụng  Trường hợp sử dụng:  Khi một đối tượng được khởi tạo từ một đối tượng khác của cùng lớp.  Khi một đối tượng được truyền như là một đối số cho hàm.  Khi hàm trả về một đối tượng.  Khi có cấp phát động thì hàm khởi tạo sao chép bắt buộc phải định nghĩa lại để tránh trường hợp con trỏ NULL (null pointer assignment).  Chương 3: Hàm và hàm đa năng trong OOP Ví dụ mẫu  Khi không có cấp phát động:  K i một đối tượng được khởi tạo từ một đối tượng khác của cùng lớp thì chương t ình tự tạo ra một hàm khởi tạo sao chép mặc định nhưng việc sao chép chỉ thực hiện bằng cách sao chép từng byte từ đối tượng nguồn sang đối tượng đích (bc).  Khi có cấp phát động: Ví dụ: CString s1(“Hello”); CString s2(s1);  Khi đối tượng được khởi tạo từ một đối tượng khác của cùng lớp mà có cấp phát động thì hàm khởi tạo sao chép mặc định sẽ KHÔNG TẠO RA vùng nhớ mới cho đối tượng s2  do đó, khi đối tượng s1 bị huỷ thì s2 sẽ trỏ vào vùng nhớ NULL c Tuso:3 Mauso:5 b Tuso:3 Mauso:5 0f003x “HELLO” s1 s2 p p Định nghĩa lại hàm khởi tạo sao chép 10  Chương 3: Hàm và hàm đa năng trong OOP  Khi không có cấp phát động:  Khi một đối tượng được khởi tạo từ một đối tượng khác của cùng lớp thì chương trình tự tạo ra một hàm khởi tạo sao chép mặc định nhưng việc sao chép chỉ thực hiện bằng cách sao chép từng byte từ đối tượng nguồn sang đối tượng đích (bc).  Khi có cấp phát động: Ví dụ: CString s1(“Hello”); CString s2(s1);  Khi đối tượng được khởi tạo từ một đối tượng khác của cùng lớp mà có cấp phát động thì hàm khởi tạo sao chép mặc định sẽ KHÔNG TẠO RA vùng nhớ mới cho đối tượng s2  do đó, khi đối tượng s1 bị huỷ thì s2 sẽ trỏ vào vùng nhớ NULL Phân số c Tuso:3 Mauso:5 b Tuso:3 Mauso:5 0f003x “HELLO” s1 s2 p p Định nghĩa lại hàm khởi tạo sao chép class Phanso{ private: int tuso,mauso; public: Phanso(); // Hàm khởi tạo không đối số Phanso(int,int); // Hàm khởi tạo 2 đối số Phanso(const Phanso&); // Hàm khởi tạo sao chép }; // Định nghĩa bên ng ài lớp: Phanso::Phanso(const Phanso& p){ tuso=p.tuso; mauso=p.mauso; } void main(){ Phanso a; // gọi hàm khởi tạo Phanso() Phanso b(3,5); // gọi hàm khởi tạo Phanso(int,int) Phanso c(b); // gọi hàm khởi tạo Phanso(const Phanso&); } 11  Chương 3: Hàm và hàm đa năng trong OOP Chuỗi class CString{ private: char *p; public: CString(); // Hàm khởi tạo không đối số CString(char *s); // Hàm khởi tạo 1 đối số CString(const CString&); // Hàm khởi tạo sao chép ~CString(); // Hàm hủy }; // Định nghĩa bên ngoài lớp: CString::CString(const CString& s) { p=strdup(s.p); } void main(){ CString s1; // gọi hàm khởi tạo CString() CString s2(“Hello world”); // gọi hàm khởi tạo CString(char *str) CString s3(s2); // gọi hàm khởi tạo CString(const CString&); } 0f003x “Hello” s1 s2 p p 0f005x “Hello” 12 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 13 Hàm với đối số ngầm định  Khái niệm  Ví dụ  Đặc điểm  Khái niệm: Là hàm mà ta đã chỉ định trước những giá trị mặc định sẽ được truyền cho các đối số trong trường hợp chúng được bỏ qua khi hàm được gọi.  Ví dụ:  Chương 3: Hàm và hàm đa năng trong OOP float divide(int a,int b=2){ return (float)a/b; } void main(){ cout<<divide(10)<<endl; cout<<divide(10,5)<<endl; }; b=2 là đối số ngầm định Giá trị ngầm định b=2 được dùng. b được gán lại = 5 14 Hàm với đối số ngầm định  Khái niệm  Ví dụ  Đặc điểm  Đặc điểm:  Nếu một đối số được gán giá trị ngầm định thì tất cả các đối số theo sau nó đều phải được gán giá trị ngầm định. Ví dụ: int divide(int a=8, int b) // error int divide(int a=8, int b=10) // ok  Giá trị ngầm định phải đúng với kiểu trong khai báo. Ví dụ: int divide(int a,int b=2.5) // error int divide(int a,int b=2) // ok  Giá trị ngầm định chỉ khai báo một lần trong khai báo hàm hoặc trong định nghĩa hàm nhưng không thể trong cả hai. Ví dụ:  Chương 3: Hàm và hàm đa năng trong OOP class PS{ int tu,mau; public: PS(int t=0,int m=1); }; PS::PS(int t=5,int m=1){ tu=t;mau=m; }  class PS{ int tu,mau; public: PS(int t=0,int m=1); }; PS::PS(int t,int m){ tu=t;mau=m; }  15 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 16 Hàm tĩnh và dữ liệu tĩnh (static)  Khái niệm  Ví dụ  Trường hợp sử dụng  Khái niệm: Dữ liệu tĩnh: là dữ liệu dùng chung cho mọi thể hiện của lớp (hữu ích trong việc chia sẻ thông tin chung giữa các đối tượng), tồn tại trong suốt quá trình chạy của chương trình. Hàm tĩnh: là hàm dùng để truy cập các thành viên dữ liệu tĩnh của lớp. Hàm này không thuộc về một đối tượng nào của lớp. Hàm được gọi ngay cả khi không có đối tượng nào được tạo bằng cách sử dụng toán tử phạm vi “::”  Cú pháp khai báo chung: dùng từ khoá static trước kiểu dữ liệu hay hàm.  Chương 3: Hàm và hàm đa năng trong OOP 17 Hàm tĩnh và dữ liệu tĩnh (static)  Khái niệm  Ví dụ  Trường hợp sử dụng  Ví dụ: Dữ liệu tĩnh  Chương 3: Hàm và hàm đa năng trong OOP class Student{ private: int MaSV; static int count; // dữ liệu tĩnh lưu trữ các thể hiện của Student public: Student(); void printCount(); ~Student(); }; int Student::count=0; // bắt buộc phải khởi tạo dữ liệu tĩnh trước khi sử dụng, gán =0 vì chưa có đối tượng nào được tạo 18 Hàm tĩnh và dữ liệu tĩnh (static)  Khái niệm  Ví dụ  Trường hợp sử dụng  Ví dụ: Hàm tĩnh  Chương 3: Hàm và hàm đa năng trong OOP class Student{ private: int MaSV; static int count; // dữ liệu tĩnh lưu trữ các thể hiện của Student public: Student(); static void printCount(); // hàm tĩnh ~Student(); }; int Student::count=0; 19 Hàm tĩnh và dữ liệu tĩnh (static)  Khái niệm  Ví dụ  Trường hợp sử dụng  Ví dụ: Hàm tĩnh  Chương 3: Hàm và hàm đa năng trong OOP class Student{ private: int MaSV; static int count; // dữ liệu tĩnh lưu trữ các thể hiện của Student public: Student(); static void printCount(); // hàm tĩnh ~Student(); }; int Student::count=0;  Trường hợp sử dụng dữ liệu tĩnh: cho biết kết quả của CT sau class Student{ private: int MaSV; static int count; // dữ liệu tĩnh lưu trữ các thể hiện của Student public: Student(); void printCount(); ~Student(); }; int Student::count=0; // bắt buộc phải khởi tạo dữ liệu tĩnh trước khi sử dụng Student::Student(){ count++; } Student::~Student(){ count--; } void Student:: printCount(){ cout<<“So doi tuong cua lop Student:”<<count<<endl; } void main(){ Student *p1=new Student; p1->printCount(); Student *p2=new Student; p1->printCount(); p2->printCount(); delete p1; p2->printCount(); } Kết quả: So doi tuong cua lop Student:1 So doi tuong cua lop Student:2 So doi tuong cua lop Student:2 So doi tuong cua lop Student:1 20 Hàm tĩnh và dữ liệu tĩnh (static)  Khái niệm  Ví dụ  Trường hợp sử dụng  Ví dụ: Hàm tĩnh  Chương 3: Hàm và hàm đa năng trong OOP class Student{ private: int MaSV; static int count; // dữ liệu tĩnh lưu trữ các thể hiện của Student public: Student(); static void printCount(); // hàm tĩnh ~Student(); }; int Student::count=0;  Trường hợp sử dụng hàm tĩnh: cho biết kết quả của CT sau class Student{ private: int MaSV; static int count; // dữ liệu tĩnh lưu trữ các thể hiện của Student public: Student(); void printCount(); ~Student(); }; int Student::count=0; // bắt buộc phải khởi tạo dữ liệu tĩnh trước khi sử dụng Student::Student(){ count++; } Student::~Student(){ count--; } void Student:: printCount(){ cout<<“So doi tuong cua lop Student:”<<count<<endl; } void main(){ Student *p1=new Student; p1->printCount(); Student *p2=new Student; p1->printCount(); p2->printCount(); delete p1; delete p2; Student::printCount(); } Kết quả: So doi tuong cua lop Student:1 So doi tuong cua lop Student:2 So doi tuong cua lop Student:2 So doi tuong cua lop Student:0 21 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 22 Hàm bạn – lớp bạn (friend)  Khái niệm  Ví dụ  Đặc điểm  Khái niệm: Hàm bạn: là hàm không phải là hàm thành viên của lớp nhưng được phép truy cập đến các thành viên dữ liệu nội tại (private) của lớp. Lớp bạn: khi tất cả hoặc phần lớn các hàm của một lớp (class B) cần truy xuất đến một lớp khác (class A) thì ta nên cho class B là bạn của class A.  Cú pháp khai báo chung: dùng từ khoá friend trước kiểu dữ liệu trả về của hàm hoặc trước từ khoá class.  Chương 3: Hàm và hàm đa năng trong OOP 23 Hàm bạn – lớp bạn (friend)  Khái niệm  Ví dụ  Đặc điểm  Ví dụ: cho biết kết quả của CT sau  Chương 3: Hàm và hàm đa năng trong OOP class PS{ private: int tu,mau; public: PS(int t=0,int m=1){ tu=t;mau=m; } friend int USCLN(PS); }; // Định nghĩa hàm bạn int USCLN(PS p){ int a=p.tu, b=p.mau; while(a!=b) a>b?a-=b:b-=a; return a; } void main(){ PS a(12,8); cout<<USCLN(a); } Kết quả: 4 Truy cập thành phần dữ liệu nội tại (private): tử,mẫu 24 Hàm bạn – lớp bạn (friend)  Khái niệm  Ví dụ  Đặc điểm  Ví dụ: cách khai báo lớp Beta là lớp bạn của lớp Alpha  Chương 3: Hàm và hàm đa năng trong OOP class Beta; class Alpha{ private: int data; public: friend class Beta; // B là bạn của A nên được phép truy xuất các thành viên dữ liệu nội tại. }; class Beta{ public: int getData_classA(Alpha a){ return A.data}; int printData_classA(Alpha a){ cout<<A.data}; }; 25 Hàm bạn – lớp bạn (friend)  Khái niệm  Ví dụ  Đặc điểm Đặc điểm:  Khi định nghĩa hàm bạn ta không cần dùng tên lớp và toán tử phạm vi “::”, từ khóa friend không xuất hiện trong định nghĩa.  Hàm bạn được gọi như các hàm truyền thống, không cần có đối tượng gọi.  Nếu B là lớp lớp bạn của A thì tất cả các hàm thành viên của lớp B có quyền truy xuất đến các thành viên dữ liệu nội tại (private) của lớp A nhưng ngược lại thì không.  Chương 3: Hàm và hàm đa năng trong OOP 26 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 27 Hàm đa năng (đa năng hóa hàm:overload)  Khái niệm  Phân loại  Ví dụ  Khái niệm: Là các hàm trong cùng một phạm vi có cùng tên và cùng thực hiện một tác vụ nào đó nhưng có danh sách các đối số khác nhau.  Phân loại:  Đa năng với các kiểu dữ liệu khác nhau  Đa năng với số lượng các đối số khác nhau Lưu ý: Hàm đa năng không xét kiểu dữ liệu trả về của các hàm  Chương 3: Hàm và hàm đa năng trong OOP 28 Hàm đa năng (đa năng hóa hàm:overload)  Khái niệm  Phân loại  Ví dụ  Ví dụ: các kiểu hàm đa năng  Chương 3: Hàm và hàm đa năng trong OOP class Alpha{ private: int data; public: int Display(int); int Display(char); // Đa năng với các kiểu dữ liệu khác nhau void Display(char,int); // Đa năng với số lượng đối số khác nhau float Display(int); // Error: đây không phài là hàm đa năng vì đã tồn tại hàm Display(int) …. }; 29 Các hàm (phương thức) truy vấn Hàm khởi tạo sao chép (copy constructor) Hàm với đối số ngầm định Hàm tĩnh và dữ liệu tĩnh (static) Hàm bạn – lớp bạn (friend) Hàm đa năng (đa năng hóa hàm:overload) Hàm chuyển đổi kiểu Hàm tại chỗ (inline)  Chương 3: Hàm (phương thức: method) và hàm đa năng trong OOP 30 Hàm chuyển đổi kiểu  Khái niệm  Phân loại  Ví dụ  Khái niệm: Là hàm dùng để chuyển đổi các đối tượng thành các kiểu dữ liệu cơ bản và ngược lại hoặc giữa các đối tượng của các lớp khác nhau (do bộ biên dịch không thể tự động chuyển đổi được các kiểu do người dùng định nghĩa). Ví dụ: - Chuyển đổi từ lớp PHANSO thành một số nguyên. - Chuyển đổi đối tượng từ mét sang đơn vị tính centimet. - …  Chương 3: Hàm và hàm đa năng trong OOP 31 Hàm chuyển đổi kiểu  Khái niệm  Phân loại  Ví dụ  Phân loại:  Đổi kiểu cơ bản thành kiểu người dùng: C1: Định nghĩa lại phép gán „=‟ C2: Khai báo và định nghĩa hàm khởi tạo chuyển đổi kiểu  Đổi kiểu người dùng thành kiểu cơ bản: Khai báo và định nghĩa một hàm chuyển đổi như là một hàm thành viên của lớp: operator  Chuyển đổi kiểu giữa các đối tượng: Cần nắm rõ lớp nguồn và lớp đích trong việc chuyển đổi mà ta cài đặt hàm khởi tạo chuyển đổi hay hàm chuyển đổi.  Chương 3: Hàm và hàm đa năng trong OOP 32 Hàm chuyển đổi kiểu  Khái niệm  Phân loại  Ví dụ  Phân loại:  Đổi kiểu cơ bản thành kiểu người dùng: C1: Định nghĩa lại phép gán „=‟ C2: Khai báo và định nghĩa hàm khởi tạo chuyển đổi kiểu  Đổi kiểu người dùng thành kiểu cơ bản: Khai báo và định nghĩa một hàm chuyển đổi như là một hàm thành viên của lớp: operator  Chuyển đổi kiểu giữa các đối tượng: Cần nắm rõ lớp nguồn và lớp đích trong việc chuyển đổi mà ta cài đặt hàm khởi tạo chuyển đổi hay hàm chuyển đổi.  Chương 3: Hàm và hàm đa năng trong OOP  Trường hợp 1: Đổi kiểu cơ bản thành kiểu người dùng: class donvi_met{ private: float met; public: donvi_met(){met=0;} donvi_met(int cm){// hàm khởi tạo chuyển đổi kiểu met=float(cm)/100; } }; void main(){ donvi_met m; int cm=100; m=cm; // gọi hàm donvi_met(int cm) } 33  Khái niệm  Phân loại  Ví dụ  Chương 3: Hàm và hàm đa năng trong OOP  Trường hợp 2: Đổi kiểu người dùng thành kiểu cơ bản: class donvi_met{ private: float met; public: donvi_met(float m){met=m;} operator int(){ return int(met*100);} // hàm chuyển đổi kiểu }; void main(){ donvi_met m(2); int cm; cm=m; // gọi hàm operator int() } 34  Khái niệm  Phân loại  Ví dụ  Chương 3: Hàm và hàm đa năng trong OOP  Trường hợp 3: Đổi kiểu giữa các đối tượng: class dv_met{ private: float met; public: dv_met(float m){met=m;} }; class dv_ centimet{ private: int centimet; public: dv_centimet(int cm){centimet=cm;} }; void main(){ dv_met m(2); dv_centimet cm(150); cm=m; m=cm; } m: lớp nguồn cm: lớp đích m: lớp đích cm: lớp nguồn Lớp đích: cài đặt hàm khởi tạo chuyển đổi kiểu Lớp nguồn: cài đặt hàm chuyển đổi kiểu operator Hoặc  Trường hợp 3: Đổi kiểu giữa các đối tượng: class dv_ centimet{ int centimet; public: dv_centimet(int cm){centimet=cm;} int getCentimet(return centimet;) }; class dv_met{ private: float met; public: dv_met(float m){met=m;} dv_met(dv_centimet cm) {met=(float)cm.getCentimet()/100;} operator dv_centimet() { return dv_centimet(int(met*100));} }; 35  Chương 3: Hàm và hàm đa năng trong OOP Cài đặt cho lớp dv_met:: - Hàm khởi tạo chuyển đổi kiểu (giải quyết trường hợp: m=cm) - Hàm chuyển đổi kiểu operator (giải quyết trường hợp: cm=m) m: lớp nguồn cm: lớp đích void main{ dv_met m(2); dv_centimet cm(150); m=cm; cm=m; } // dv_met(dv_centimet cm) // operator dv_centimet()  Bảng tóm tắt: Đổi kiểu giữa các đối tượng:  Ví dụ:  Từ cơ bản  lớp A A obj; obj=5;  Từ lớp A  cơ bản A obj; int i; i=obj;  Từ lớp A  lớp B A a; B b; a=b; 36  Chương 3: Hàm
Tài liệu liên quan