Cơ bản về hướng đối tượng và C++

Một số hệ Unix chứa khoảng 4M dòng lệnh • Một số hệ Unix chứa khoảng 4M dòng lệnh • MS Windows chứa hàng chụctriệu dòng lệnh •Người dùng ngày càng đòi hỏi nhiều chức năng, đặc biệt là chức năng thông minh • Phần mềm luôn cần được sửa đổi

pdf31 trang | Chia sẻ: haohao89 | Lượt xem: 2096 | Lượt tải: 3download
Bạn đang xem trước 20 trang tài liệu Cơ bản về hướng đối tượng và C++, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
1• Bài giảng LTHĐT, Trần Minh Châu, Đại học Công nghệ ĐH Quốc gia HN , • Bài giảng LTHĐT, Nguyễn Việt Hà, Đại học Công nghệ ĐH Quốc gia HN , • Bài giảng LTHĐT, Nguyễn Ngọc Long, ĐH KHTN TPHCM • Bài giảng LTHĐT, Huỳnh Lê Tấn Tài, ĐH KHTN TPHCM • C++ How to Program, Dietel • ………………………. 2 • Tạo ra sản phẩm tốt một cách có hiệu quả • Nắm bắt được công nghệ 3 • Một số hệ Unix chứa khoảng 4M dòng lệnh • MS Windows chứa hàng chục triệu dòng lệnh • Người dùng ngày càng đòi hỏi nhiều chức năng, đặc biệt là chức năng thông minh • Phần mềm luôn cần được sửa đổi 4 • Cần kiểm soát chi phí – Chi phí phát triển Chi phí bảo trì– • Giải pháp chính là sử dụng lại(tái sử dụng) – Giảm chi phí và thời gian phát triển ấ– Nâng cao ch t lượng 5 • Cần dễ hiểu • Được coi là chính xác • Có giao diện rõ ràng • Tính module hóa • Không yêu cầu thay đổi khi sử dụng trong chương trình mới 6 • Lập trình không có cấu trúc • Lập trình có cấu trúc (lập trình thủ tục),hướng chức năng • Lập trình logic, lập trình hàm • Lập trình hướng đối tượng 7 • Là phương pháp xuất hiện đầu tiên – các ngôn ngữ như Assembly, Basic – sử dụng các biến toàn cục – lạm dụng lệnh GOTO • Các nhược điểm – khó hiểu, khó bảo trì, hầu như không thể sử dụng lại – chất lượng kém – chi phí cao – không thể phát triển các ứng dụng lớn 8 Ví dụ 10 k =1 20 gosub 100 30 if y > 120 goto 60 40 k = k+1 50 goto 20 60 print k y , 70 stop 100 3*k*k 7*k 3 y = + - 110 return 9 • Tổ chức thành các chương trình con(hay các module) • Mỗi chương trình con đảm nhận xử lý một công việc nhỏ hay một nhóm công việc trong toàn bộ hệ thống • Mỗi chương trình con này lại có thể chia nhỏ thành các chương trình con nhỏ hơn ấChương trình = C u trúc dữ liệu + Giải thuật 10 • sử dụng các lệnh có cấu trúc: for, do, while, if then else ... • các ngôn ngữ: Pascal, C, ... ủ• chương trình là tập các hàm/th tục • Ưu điểm – chương trình được module hóa, do đó dễ hiểu, dễ bảo trì hơn – dễ dàng tạo ra các thư viện phần mềm 11 Ví dụ struct Date { int year, mon, day; }; ... void print_date(Date d) { printf(”%d / %d / %d\n”, d.day,d.mon,d.year); } 12 • Nhược điểm – dữ liệu và mã xử lý là tách rời – người lập trình phải biết cấu trúc dữ liệu (vấn đề này một thời gian dài được coi là hiển nhiên) khi th đổi ấ t ú dữ liệ thì ã ử lý (th ật– ay c u r c u m x u toán) phải thay đổi theo – khó đảm bảo tính đúng đắn của dữ liệu – không tự động khởi tạo hay giải phóng dữ liệu động – không mô tả được đầy đủ, trung thực hệ thống trong thực tế 13 • Trong thế giới thực, chung quanh chúng ta là những đối tượng đó là các thực thể có mối, quan hệ với nhau. Ví dụ: các phòng trong một công ty • Lập trình hướng đối tượng (Object Oriented Programming LTHĐT) là phương pháp lập- trình lấy đối tượng làm nền tảng để xây dựng thuật giải xây dựng chương trình, 14 • Đối tượng (object): – Trong thế giới thực, khái niệm đối tượng được hiểu như là một thực thể: người, vật hoặc một bảng dữ liệu…. – Mỗi đối tượng sẽ tồn tại trong một hệ thống và có ý nghĩa nhất định trong hệ thống. – Đối tượng giúp biểu diễn tốt hơn thế giới thực trên máy tính 15 • Lớp: – Các đối tượng có các đặc tính tương tự nhau được gom chung lại thành lớp đối tượng Ví dụ. Người là một lớp đối tượng. Một lớp đối tượng được đặc trưng bằng các thuộc tính, và các hoạt động (hành vi, thao tác). – Thuộc tính (attribute) là một thành phần của đối tượng, có giá trị nhất định cho mỗi đối tượng tại mỗi thời điểm trong hệ thống. Vd: Tên, Tuổi, Cân à á ộ í ủ ờnặng l c c thu c t nh c a Ngư i – Thao tác (operation) thể hiện hành vi của một đối t tá độ l i ới á đối tượng c ng qua ạ v c c ượng khác hoặc với chính nó. 16 ỗ ố ể• M i thao tác trên một lớp đ i tượng cụ th tương ứng với một cài đặt cụ thể khác nhau. Một ài đặt h ậ đ i là ột hc n ư v y ược gọ m p ương thức (method). ể• Cùng một thao tác(phương thức) có th được áp dụng cho nhiều lớp đối tượng khác nhau, ột th tá h ậ đ i là ó tí h đm ao c n ư v y ược gọ c n a hình (polymorphism). ố ể• Một đ i tượng cụ th thuộc một lớp được gọi là một thể hiện (instance) của lớp đó. ổ ể– Joe Smith, 25 tu i, nặng 58kg, là một th hiện của lớp người. 17 • Ta dùng sơ đồ đối tượng để mô tả các lớp đối tượng. Sơ đồ đối tượng bao gồm sơ đồ lớp và sơ đồ thể hiện • Sơ đồ lớp mô tả các lớp đối tượng trong hệ thống, một lớp đối tượng được diễn tả bằng một hình chữ nhật có 3 phần: – phần đầu chỉ tên lớp, – phần thứ hai mô tả các thuộc tính – phần thứ ba mô tả các thao tác của các đối tượng trong lớp đó. 18 Sinh vieân Hoï teân N ê i h (Sinh vieân) Nguyeãn Vaên A 1984 Teân lôùp am s n Maõ soá Ñieåm TB 0610234T 9 2 Thuoäc tính Ñi hoïc Ñi thi . Thao taùc Phaân loaïi Sô ñoà lôùp Sô ñoà theå hieän ốĐ i tượng = Dữ liệu + Phương thức 19 • Các lớp đối tượng - Classes • Đóng gói – Encapsulation ế• Thừa k - Inheritance • Đa hình - Polymorphism 20 cách nhìn khái quát hóa về một tập các đối tượng có chung các đặc điểm được quan tâm (và bỏ qua những chi tiết không cần thiết). 21 • Đóng gói: Nhóm những gì có liên quan với nhau vào làm một, để sau này có thể dùng một cái tên để gọi đến – Các hàm/ thủ tục đóng gói các câu lệnh – Các đối tượng đóng gói dữ liệu của chúng và các thủ tục có liên quan • Che dấu thông tin: đóng gói để che một số thông tin và chi tiết cài đặt nội bộ để bên ngoài không nhìn thấy – che giấu những gì mà người dùng không cần – che giấu những gì mà mình cần giữ bí mật 22 • là cơ chế cho phép một lớp D có được các thuộc tính và thao tác của lớp C, như thể các thuộc tính và thao tác đó đã được định nghĩa tại lớp D. • cho phép cài đặt nhiều quan hệ giữa các đối tượng: đặc biệt hóa (“là”), khái quát hóa 23 cơ chế cho phép một tên thao tác hoặc thuộc tính có thể được định nghĩa tại nhiều lớp và có thể có nhiều cài đặt khác nhau tại mỗi lớp trong các lớp đó 24 • Cung cấp được những khả năng lập trình hướng đối tượng – cung cấp khả năng kiểm soát truy cập – kế thừa – đa hình 25 26 • OOM (Object Oriented Methodology): Phương pháp luận hướng đối tượng • OOA (Object Oriented Analysis): Phân tích hướng đối tượng. • OOD: Object Oriented Design (Thiết kế hướng đối tượng). • OOP: Object Oriented Programming (lập trình hướng đối tượng). • Inheritance: Kế thừa • Polymorphism: Đa hình • Encapsulation: Tính đóng gói. 27 • Nguyên lý kế thừa: tránh lặp, tái sử dụng. Ng ên lý đóng gói ha che dấ thông tin: h• uy y u c ương trình an toàn không bị thay đổi bới những đoạn chương trình khác • Dễ mở rộng, nâng cấp • Mô phỏng thế giới thực tốt hơn. 28 • Chương trình được chia thành các đối tượng. • Các cấu trúc dữ liệu được thiết kế sao cho đặc tả được đối tượng. • Các hàm thao tác trên các vùng dữ liệu của đối tượng được gắn với cấu trúc dữ liệu đó. 29 • Dữ liệu được đóng gói lại, được che giấu và không cho phép các hàm ngoại lai truy nhập tự do. • Các đối tượng tác động và trao đổi thông tin với nhau qua các hàm • Có thể dễ dàng bổ sung dữ liệu và các hàm mới vào đối tượng nào đó khi cần thiết • Chương trình được thiết kế theo cách tiếp cận từ d ới lê (b )ư n ottom-up . 30 – Mở rộng của C – Đầu thập niên 1980: Bjarne Stroustrup (Bell Laboratories) – Cung cấp khả năng lập trình hướng đối tượng • Objects • Object-oriented programs – Ngôn ngữ lai • C-like style • Object-oriented style • Both 31 • Chú thích • Các kiểu dữ liệu • Kiểm tra kiểu, đổi kiểu Ph i à kh i bá• ạm v v a o • Không gian tên ằ• H ng • Quản lý bộ nhớ ế• Tham chi u 32 #include void main() { int n; double d; char s[100]; cout << “Input an int, a double and a string ”;. cin >> n >> d >> s; cout << “n = “ << n << “\n”; t “d “ d “\ ”cou << = << << n ; cout << “s = “ << s << “\n”; } 33 Th hi á l ø ñò hæ ø hôù ñöô á h ùt h• am c eu a a c vung n ïc cap p a c o moät bieán. • Kyù hieäu & ñaët tröôùc bieán hoaëc haøm ñeå xaùc ñònh tham chieáu cuûa chuùng • Ví duï 1: int x = 10 *px = &x &y = x;– , , – *px = 20; // *px = x = y = 20 – y = 30; // y = x = *px = 30 • Ví du 2: ï – int arrget(int *a, int i) { return a[i]; } – arrget(a, 1) = 1; // a[1] = 1; – cin >> arrget(a,1); // cin >> a[1]; • Ví duï 3: – void swap1(int x, int y) { int t = x; x = y; y = t; } – void swap2(int *x, int *y) { int *t = x; x = y; y = t; } – void swap3(int &x, int &y) { int t = x; x = y; y = t; } 34 Choàng haøm (Functions overloading int abs(int i); long labs(long l); double fabs(double d); int abs(int i); long abs(long l); double abs(double d); int abs(int i) { return abs(i);} long abs(long l) { return labs(l);} double abs(double d) { return fabs(d);} void test_abs() { int i = abs(10); // abs(int ) long l = abs(-10l); // abs(long ) double = abs(0.1l); // abs(double ) } 35 Tham soá ngaàm ñònh trong lôøi goïi haøm void inc(int &a, int b = 1) { a = a + b; } int x = 5, y = 10; inc(x 10); // x = x + 10 Chuù yù: , inc(y); // y = y + 1 – Caùc tham soá coù giaù trò ngaàm ñònh phaûi ñaët cuoái danh saùch tham soá, ñeå traùnh nhaàm laãn caùc giaù trò. – Caùc giaù trò ngaàm ñònh cuûa tham soá chæ ñöôïc khai baùo trong khuoân maãu haøm 36 • Toaùn töû caáp phaùt boä nhôù ñoäng new int *x; x = new int; // x = (int*)malloc(sizeof(int)); char *y; y = new char[100]; // y = (char*)malloc(100); • Toaùn töû giaûi phoùng vuøng nhôù ñoäng delete delete x; // free(x); delete y; // free(y); 37 • Nên khai báo hằng đối với: Các đối tượng mà ta không định sửa đổi– – const double PI = 3.14; – const Date openDate(18,8,2003); – Các tham số của hàm mà ta không định cho hàm đó sửa đổi id i tH i ht( t L Obj &LO)– vo pr n e g cons arge { cout << LO.height; } – Các hàm thành viên không thay đổi đối tượng chủ – int Date::getDay() const { return day; } 38 • Một lớp bao gồm các thành phần dữ liệu hay là thuộc tính và các phương thức hay là hàm thành phần • Lớp trong C++ thực chất là một kiểu dữ liệu do người sử dụng định nghĩa 39 • Lưu giữ trạng thái: mỗi đối tượng có trạng thái (dữ liệu của nó) và các thao tác • Định danh: Mỗi đối tượng bất kể đang ở trạng thái nào đều có định danh và được đối xử như một thực thể riêng biệt. • Thông điệp: là phương tiện để một đối tượng A chuyển tới đối tượng B yêu cầu B thực hiện một trong số các thao tác của B. 40 • Lớp: là khuôn mẫu để tạo các đối tượng (tạo các thể hiện). Mỗi đối tượng có cấu trúc và hành vi giống như lớp đối tượng mà nó được tạo từ đó. • Lớp là cái ta thiết kế và lập trình Đối t là ái t t (từ ột lớ ) t i thời i• ượng c a ạo m p ạ g an chạy. 41 class { private: <khai báo các thành phần riêng trong từng đối tượng> protected: <khai báo các thành phần riêng trong từng đối tượng, có thể truy cập từ lớp dẫn xuất > public: <khai báo các thành phần giao tiếp của từng đối tượng> }; <đị h hĩ ủ á hà thà h hầ h đn ng a c a c c m n p n c ưa ược định nghĩa bên trong khai báo lớp> 42 :: (<danh sách tham số>) { } void point::display() { } …….. 43 • Tạo đối tượng: = new • Gọi hàm thành phần của lớp (<d hn ư ng . n m n p n an sách các tham số nếu có>); Æ<tên hàm thành phần>(); 44 • Xây dựng lớp Điểm (Point) trong hình học 2D – Thuộc tính • Tung độ • Hoành độ – Thao tác (phương thức) • Khởi tạo • Di chuyển • In ra màn hình • ………….. 45 /* i t */po n .cpp #include #include class point { /*khai báo các thành phần dữ liệu riêng*/ private: int x,y; /*khai báo các hàm thành phần công cộng*/ public: void init(int ox, int oy); id (i t d i t d )vo move n x, n y ; void display(); }; 46 void point::init(int ox, int oy) { cout<<"Ham thanh phan init\n"; x = ox; y = oy; /*x,y là các thành phần của đối tượng gọi hàm thành phần*/ } void point::move(int dx, int dy) { cout<<"Ham thanh phan move\n"; x += dx; y += dy; } void point::display() { cout<<"Ham thanh phan display\n"; cout<<"Toa do: "<<x<<" "<<y<<"\n"; } 47 void main() { clrscr(); point p; p.init(2,4); /*gọi hàm thành phần từ đối tượng*/ p.display(); p.move(1,2); p.display(); getch(); } 48 Ham thanh phan init Ham thanh phan display Toa do: 2 4 H th h ham an p an move Ham thanh phan display 3 6Toa do: 49 • Trong định nghĩa của lớp ta có thể xác định khả năng truy xuất thành phần của một lớp nào đó từ bên ngoài phạm vi lớp • private và public là các từ khoá xác định thuộc tính truy xuất • Mọi thành phần được liệt kê trong phần public đều có thể truy xuất trong bất kỳ hàm nào • Những thành phần được liệt kê trong phần private chỉ được truy xuất bên trong phạm vi lớp 50 • Trong lớp có thể có nhiều nhãn private và public • Mỗi nhãn này có phạm vi ảnh hưởng cho đến khi gặp một nhãn kế tiếp hoặc hết khai báo lớp • Nhãn private đầu tiên có thể bỏ đi vì C++ ngầm hiểu rằng các thành phần trước nhãn public đầu tiên là private 51 class tamgiac{ i tpr va e: float a,b,c;/*độ dài ba cạnh*/ public: void nhap();/*nhập vào độ dài ba cạnh*/ void in();/*in ra các thông tin liên quan đến tam giác*/ private: int loaitg();/*cho biết kiểu của tam giác: 1-d,2-vc,3-c,4-v,5-t*/ float dientich();/*tính diện tích của tam giác*/ }; 52 class tamgiac{ private: float a b c;/*độ dài ba cạnh*/ , , int loaitg();/*cho biết kiểu của tam giác: 1-d,2-vc,3-c,4-v,5-t*/ float dientich();/*tính diện tích của tam giác*/ public: void nhap();/*nhập vào độ dài ba cạnh*/ void in();/*in ra các thông tin liên quan đến tam giác*/ }; 53 Đối tượng như tham số của hàm thành phần • Hàm thành phần có quyền truy nhập đến các thành phần private của đối tượng gọi nó: void point::init(int xx,int yy) { x=xx; y=yy; } 54 Đối tượng như tham số của hàm thành phần • Hàm thành phần có quyền truy nhập đến tất cả các thành phần private của các đối tượng, tham chiếu đối tượng hay con trỏ đối tượng có cùng kiểu lớp khi được dùng là tham số hình thức của nó int trung(point pt) {return(x==pt.x && y==pt.y);} int trung(point *pt) {return(x==pt->x && y==pt->y);} int trung(point &pt) {return(x==pt.x && y==pt.y);} 55 • Từ khoá this trong định nghĩa của các hàm thành phần lớp dùng để xác định địa chỉ của đối tượng dùng làm tham số ngầm định cho hàm thành phần • Con trỏ this tham chiếu đến đối tượng đang gọi hàm thành phần int trung(point pt) {return(this->x==pt.x && this->y==pt.y);} 56 point a, b; việc sao chép giá trị các thành phần ốa.init(5,2); b=a; dữ liệu (x, y) từ đ i tượng a sang đối tượng b tương ứng từng đôi một ba 5 x5x 2 y2y 57 • Nếu hai đối tượng A và B cùng kiểu, có các thành phần dữ liệu x,y(tĩnh) và z là một con trỏ chỉ đến một vùng nhớ được cấp phát động ba 2 y 5 5 2 x y x zzSao chép bề mặt vùng dữ liệu động58 • Constructor là một loại phương thức đặc biệt dùng để khởi tạo thể hiện của lớp • Bất kể loại cấp phát bộ nhớ nào được sử dụng (tự động tĩnh động) mỗi khi một thể hiện của, , , lớp được tạo, một hàm constructor nào đó của lớp sẽ được gọi 59 class point { /*khai báo các thành phần dữ liệu*/ int x; int y; public: /*khai báo các thành phần hàm*/ point(int ox,int oy) {x=ox;y=oy;}/*hàm thiết lập*/ void move(int dx,int dy) ; void display(); }; point a(5,2); //int i(5) 60 • Constructor có cùng tên với tên của lớp • Constructor không có giá trị trả về (kể cả void) • Constructor phải có thuộc tính public C t t ó thể đ kh i bá hồ h• ons ruc or c ược a o c ng n ư các hàm C++ thông thường khác Constructor có thể được khai báo với các tham• số có giá trị ngầm định 61 class point { /*khai báo các thành phần dữ liệu*/ int x; int y; public: /*khai báo các thành phần hàm*/ point() {x=0;y=0}; point(int ox,int oy) {x=ox;y=oy;}/*hàm thiết lập*/ void move(int dx,int dy) ; void display(); }; point a(5,2); point b; point c(3); 62 class point { /*khai báo các thành phần dữ liệu*/ int x; int y; public: /*khai báo các thành phần hàm*/ point() {x=0;y=0}; point(int ox,int oy=1) {x=ox;y=oy;}/*hàm thiết lập*/ void move(int dx,int dy) ; void display(); }; point a(5,2); point b; point c(3); 63 • Constructor mặc định (default constructor) là constructor được gọi khi thể hiện được khai báo ố ố ấmà không có đ i s nào được cung c p • MyClass x; M Cl * M Cl• y ass p = new y ass; • Ngược lại, nếu tham số được cung cấp tại khai báo thể hiện trình biên dịch sẽ gọi phương thức , constructor khác (overload) • MyClass x(5); • MyClass* p = new MyClass(5); 64 • Đối với constructor mặc định, nếu ta không cung cấp một phương thức constructor nào, C++ sẽ tự sinh constructor mặc định là một phương thức rỗng ế• Tuy nhiên, n u ta không định nghĩa constructor mặc định nhưng lại có các constructor khác, trình biên dịch sẽ báo lỗi không tìm thấy constructor mặc định nếu ta không cung cấp tham số khi tạo thể hiện. 65 class point { /*khai báo các thành phần dữ liệu*/ int x; int y; public: ầ/*khai báo các thành ph n hàm*/ point(int ox,int oy=1) {x=ox;y=oy;}/*hàm thiết lập*/ void move(int dx int dy) ; , void display(); }; point a(5,2); point b; point c(3); 66 class point { /*khai báo các thành phần dữ liệu*/ int x; int y; public: /*khai báo các thành phần hàm*/ point(int ox=0,int oy=0) {x=ox;y=oy;}/*hàm thiết lập*/ void move(int dx,int dy) ; void display(); }; point a(5 2); , point b; point c(3); 67 68 • Cũng như một phương thức constructor được gọi khi một đối tượng được tạo, loại phương thức thứ hai, destructor, được gọi ngay trước khi thu hồi một đối tượng • Destructor thường được dùng để thực hiện mọi việc dọn dẹp cần thiết trước khi một đối tượng bị huỷ • Destructor không có giá trị trả về, và không thể định ốnghĩa lại (nó không bao giờ có tham s ) • Phương thức destructor trùng tên với tên lớp nhưng có dấu ~ đặt trước • Destructor phải có thuộc tính public 69 class vector { i t // ố hiền n; s c u float *v; //vùng nhớ toạ độ public: vector(); //Hàm thiết lập không tham số vector(int size); //Hàm thiết lập một tham số vector(int size, float *a); ~vector();//Hàm huỷ bỏ luôn luôn không có tham số , void display(); }; 70 • Giả sử có lớp Vector, lớp Matrix • Cần viết hàm nhân 1 Vector và 1 Matrix • Hàm nhân: Khô thể th ộ lớ V t– ng u c p ec or – Không thể thuộc lớp Matrix Không thể tự do– • Giải pháp: xây dựng hàm truy cập dữ liệu. 71 • Hàm bạn không thuộc lớp, nhưng có quyền truy cập các thành viên private. • Khi định nghĩa một lớp, có thể khai báo rằng một hay nhiều hàm “bạn” (bên ngoài lớp) • Ưu điểm: kiểm soát các truy nhập ở cấp độ lớp - không thể áp đặt hàm bạn cho một lớp nếu điều đó không được dự trù trước trong khai báo của lớp 72 • Hàm tự do là bạn của một lớp. • Hàm thành phần của một lớp là bạn của một lớp khác. • Hàm bạn của nhiều lớp . • Tất cả các hàm thành phần của một lớp là bạn của một lớp khác 73 class point { int x y; , public: point(int abs =0 int ord =0) { , x = abs;y = ord; } friend int coincide (point,point); }; 74 • Vị trí của khai báo “bạn bè” trong lớp hoàn toàn tuỳ ý • Trong hàm bạn, không còn tham số ngầm định this như trong hàm thành phần • Hàm bạn của một lớp có thể có một hay nhiều tham số, hoặc có giá trị trả về thuộc kiểu lớp đó 75 76 • Các phương thức truy vấn (query method) là các phương thức dùng để hỏi về giá trị của các thành viên dữ liệu của một đối tượng • Có nhiều loại câu hỏi truy vấn có thể: tr ấn đơn giản (“giá trị của là bao nhiê ?”)– uy v x 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 quan trọng của phương thức truy vấn là nó không nên thay đổi trạng thái hiện tại của đối tượng 77 • Đối với các truy vấn đơn giản, quy ước đặt tên phư
Tài liệu liên quan