Lập trình hướng đối tượng C++

153 374 1
Lập trình hướng đối tượng C++

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Lập trình hướng đối tượng C++

1 MỤC LỤC Lời nói đầu 4 Chương 1: Mở đầu 6 1.1. So sánh giữa lập trình hướng đối tượnglập trình hướng thủ tục6 1.1.1 Lập trình hướng thủ tục 6 1.1.2 Lập trình hướng đối tượng 7 1.2. Giới thiệu ngôn ngữ C++ 8 1.2.1 Chú thích trong C và trong C++ 8 1.2.2 Các từ khóa mới 8 1.2.3 Phép chuyển kiểu bắt buộc 8 1.2.4 Khai báo biến 8 1.2.5 Hàm main 9 1.2.6 Truyền tham số cho hàm 10 1.2.7 Nhắc lại về biến con trỏ 13 1.2.8 Sử dụng tham số truyền ngầm định trong hàm 15 1.2.9 Cấp phát và giải phóng bộ nhớ 16 1.2.10. Các hàm tải bội (Overloaded function) 17 1.2.11. Hàm inline 18 1.2.12. Khả năng vào ra mới của C++ 21 1.3. Bài tập chương 1 23 Chương 2: Lớp các đối tượng 27 2.1. Lớp các đối tượng 27 2.1.1 Các khái niệm cơ bản 27 2.1.2 Khai báo lớp các đối tượng 27 2.1.3 Các thành phần trong lớp (Data member and function member) 31 2.1.4 Đối tượng trong tham số của hàm 42 2.2. Constructor và destructor 44 2.2.1 Khái niệm chung 44 2.2.2 Khai báo và định nghĩa constructor và destructor 44 2.2.3 Con trỏ this 46 2.3. Toán tử tải bội và toán tử tải bội thân thiện 48 Nguyễn Chí Trung 2 2.3.1. Khái quát chung 48 2.3.2 Toán tử tải bội 48 2.3.3 Toán tử tải bội thân thiện 52 2.3.4 Chuyển đổi kiểu 59 2.4. Vài vấn đề về sử dụng từ khoá const 66 2.4.1 Sử dụng biến kiểu const 66 2.4.2 Truyền tham số kiểu const cho hàm 67 2.4.3 Đối tượng hằng của lớp 68 2.4.4.Hàm thành phần const (hàm thành phần có khai báo const phía sau) 70 2.4.5.Con trỏ this kiểu const (hàm thành phần có khai báo const phía trước) 72 2.4.6 Nghiên cứu lớp String 73 2.4.7 Đọc thêm về lớp các dãy bit 78 2.5. Bài tập chương 2 81 Chương 3: Sự kế thừa 84 3.1. Sự tương ứng trong kế thừa 84 3.1.1 Khái niệm chung 84 3.1.2 Kế thừa đơn 86 3.1.3 Thành phần protected trong kế thừa 88 3.1.4 Kế thừa đa mức 92 3.1.5 Kế thừa phân cấp 93 3.1.6 Kế thừa bội 94 3.1.7 Kế thừa kép (lai ghép) 95 3.1.8 Constructor trong các lớp kế thừa 99 3.2. Con trỏ xác định thành phần của lớp và con trỏ xác định đối tượng 102 3.2.1 Các quy tắc cú pháp về con trỏ 102 3.2.2.Các ví dụ minh hoạ cách sử dụng con trỏ xác định đối tượng và thành phần (dữ liệu và hàm) của lớp 103 3.2.3 Con trỏ xác định đối tượng 105 3.3. Hàm ảo và tương ứng bội trong kế thừa 106 3.3.1 Các hàm dịch chuyển (Override function) 106 3.3.2 Con trỏ xác định đối tượng trong quan hệ kế thừa 107 Nguyễn Chí Trung 3 3.3.3. Con trỏ hàm ảo và tương ứng bội 108 3.3.4 Kế thừa lai ghép và lớp cơ sở ảo 111 3.3.5 Hàm rỗng (Null Function) 114 3.3.6 Hàm ảo thực sự và lớp trừu tượng (pure function & abstract class) 115 3.3.7 Hàm thân thiện ảo và toán tử ảo dịch chuyển 116 3.4. Bài tập chương 3 116 Chương 4: Làm việc với Tệp 120 4.1. Các Thao tác cơ bản với tệp 120 4.1.1 Đọc dữ liệu từ tệp 120 4.1.2 Ghi dữ liệu vào tệp 122 4.2. Một số vấn đề khác làm việc với tệp 125 4.2.1 Mở tệp bằng open 125 4.2.2 Các chế độ làm việc với tệp 125 4.2.3 Đọc/ ghi tệp nhị phân 126 4.3. Bài tập chương 4 128 Phụ lục 1: Lớp mẫu và hàm mẫu 130 Khái quát 130 4.3.2 Hàm mẫu 130 4.3.3 Lớp mẫu 132 Phụ lục 2: Giới thiệu Một số bài toán phân tích thiết kế hướng đối tượng trên C++ 137 4.3.1 Sơ lược 5 bước thực hiện 137 4.3.2 Xây dựng lớp hình học phẳng 137 4.3.3 Quản lý các lô đất 146 Tài liệu tham khảo 153 Nguyễn Chí Trung 4 LỜI NÓI ĐẦU Lập trình trên ngôn ngữ C là một một ví dụ về phương pháp tiếp cận lập trình hướng chức năng. Phương pháp này tập trung vào thuật toán chính để giải quyết bài toán đặt ra và có thể phải phân rã bài toán xuất phát này thành các bài toán con nhỏ hơn. Việc tìm thuật toán cho từng bài toán con thậm chí lại phải tiếp tục chia thành các bài toán con nhỏ hơn nữa và quá trình đó là quá trình làm mịn dần, có nghĩa là việc phân chia thành các bài toán con sẽ dừng lại cho đến khi thu được tập các bài toán con đơn giản nhất, có thể tìm ngay ra lời giải. Khi xây dựng các phần mềm lớn, phương pháp lập trình hướng chức năng đã gặp khó khăn trong việc cập nhật và sửa đổi, có nghĩa là việc thay đổi một phần chức năng và dữ liệu trong chương trình có thể làm ảnh hưởng đến toàn bộ hệ thống và mất nhiều công sức để điều ch ỉnh. Cần phải có một hướng tiếp cận khác trong lập trình để hạn chế được những nhược điểm của lập trình truyền thống: trước tiên phải chú trọng đến những đối tượng xuất hiện trong bài toán, tìm cách đặc tả đối tượng (gồm thông tin và hành vi) sao cho phù hợp với thế giới thực. Có nghĩa là thay vì quan tâm đến chức năng, nhiệm vụ đã đặt ra, kỹ thu ật lập trình mới sẽ đặt trọng tâm vào việc xử lý các dữ liệu để thực hiện các chức năng đó. Kỹ thuật lập trình mới này mang tên là kỹ thuật lập trình hướng đối tượng (Object Oriented Programing) và trên kỹ thuật này nhiều trình biên dịch đã được thiết kế, trong đó có C++. Việc sử dụng C++ bao gồm những thuận lợi và những khó khăn. Lớp các đối tượng của C++ cho phép cài đặ t riêng rẽ giao diện (interface) và thể hiện (implementation) và có thể ẩn việc thể hiện chi tiết ở bên trong. Rõ ràng C++ hỗ trợ khái niệm trừu tượng cũng giống như là một số ngôn ngữ khác hỗ trợ nó đặc biệt như là Pascal, C . Sự thuận lợi của C++C++ có thể sử dụng rộng rãi trong nhiều ngành nghề, học sinh có thể nắm bắt được các kỹ năng lý thuyết cũ ng như thực hành và điều này giúp họ có thể tìm kiếm việc làm dễ dàng. Nhưng sự khó khăn của C++ là nó khác xa ngôn ngữ sư phạm và vì vậy cần phải chú ý về mặt thực hành để có thể đạt được kỹ năng lập trình nhất định. Điều không thuận lợi thứ hai là C++ vẫn không phải là ngôn ngữ cố định vì vậy có các chương trình dịch khác nhau. C++ mà chúng ta sẽ sử d ụng đi cùng với tài liệu này là Turbo C++ version 3.0 của Borland (1990 - 1992). Lời cảm ơn Tác giả xin bầy tỏ lòng biết ơn chân thành tới: Phó giáo sư, tiến sỹ Nguyễn Xuân Huy (Viện Công nghệ thông tin); Giáo sư Phạm Văn Ất (Đại học giao thông); Tiến sỹ Dương Tử Cường (Học viện kỹ thuật quân sự); Tiến sỹ Phó Đức Toàn (Đại học sư phạm Hà Nội I); Phó giáo sư, tiến sỹ Đoàn Văn Ban (Viện Công nghệ thông tin) đã có những ý kiến đóng góp quý báu để cuốn giáo trình được hoàn chỉnh và có chất lượng hơn. Nguyễn Chí Trung 5 Tác giả cũng xin chân thành cảm ơn sự tổ chức, hợp tác và giúp đỡ nhiệt tình của Ban giám hiệu, phòng Đào tạo và tổ chuyên môn trường THKT Tin học Hà Nội - ESTIH. Nguyễn Chí Trung 6 MỞ ĐẦU SO SÁNH GIỮA LẬP TRÌNH HƯỚNG ĐỐI TƯỢNGLẬP TRÌNH HƯỚNG THỦ TỤC Lập trình hướng thủ tục  Theo cách tiếp cận truyền thống của lập trình hướng thủ tục thì chương trình được xem như dãy các công việc cần thực hiện: Nhập dữ liệu, Xử lý dữ liệu, Tính toán, Lập báo cáo, In kết quả  Vậy trọng tâm của lập trình h ướng thủ tục là phân rã bài toán thành các hàm chức năng theo kỹ thuật top-down. Bài toán được giải quyết bởi một số hàm chính. Các hàm chính lại có thể phân chia thành các bài toán con - tức là các hàm chức năng nhỏ hơn nữa. Một số hàm có thể gọi thực hiện (dùng chung) một số hàm chức năng nhỏ hơn. Như vậy, cấu trúc các hàm của một chương trình lập trình hướng thủ tục là cấu trúc phân cấp các hàm:  Việc chú ý tới các hàm trong chương trình sẽ không quan tâm nhiều đến dữ liệu. Dữ liệu của toàn bộ chương trình được các hàm dùng chung và biến đổi từ hàm này sang hàm khác. Bản thân trong các hàm cũng có dữ liệu riêng. • Vậy đặc trưng của lập trình hướng thủ tục là 1. Tập trung vào công việc cần thực hiện - thuật toán. 2. Chương trình được chia thành các hàm nhỏ. 3. Phần lớn các hàm dùng chung dữ li ệu. 4. Dữ liệu trong chương trình chuyển động từ hàm này sang hàm khác. main Hàm1 Hàm2 Hàm3 Hàm4 Hàm5 Hàm6 Hàm7 Hàm8 Dữ liệu chung Dữ liệu chung Hàm 1 Dữ liệu riêng 1 Hàm 2 Dữ liệu riêng 2 Hàm 3 Dữ liệu riêng 3 Nguyễn Chí Trung 7 5. Hàm biến đổi dữ liệu từ dạng này sang dạng khác. 6. Thiết kế chương trình theo kỹ thuật top-down Lập trình hướng đối tượngLập trình hướng đối tượng đặt trọng tâm vào đối tượng và không cho dữ liệu chuyển động trong hệ thống. Dữ liệu gắn chặt vào các hàm và thủ tục tạo thành một vùng riêng và không cho các hàm bên ngoài truy nhập một cách tuỳ tiện. • Lập trình hướng đối tượng phân tích bài toán thành các th ực thể gọi là đối tượng, sau đó xây dựng các hàm xung quanh đối tượng đó. • Dữ liệu của đối tượng chỉ có thể truy nhập được bởi các hàm của đối tượng. Chỉ có một số hàm của đối tượng này có thể gọi thực hiện các hàm của đối tượng khác biểu thị sự trao đổi thông báo giữa các đối tượng. • Nh ư vậy đặc trưng của lập trình hướng đối tượng là: 1. Tập trung vào dữ liệu thay cho hàm. 2. Chia chương trình thành các đối tượng. 3. Dữ liệu được thiết kế sao cho đặc tả được đối tượng. 4. Các hàm được xây dựng trên các vùng dữ liệu của đối tượng và được gắn liền với nhau trên cấu trúc dữ liệu đó. 5. Dữ liệu được bao bọc, che dấu không cho các hàm ngoại lai truy nhập. 6. Các đối tượng trao đổi thông báo với nhau thông qua các hàm. 7. Dữ liệu và các hàm dễ dàng bổ sung vào đối tượng. 8. Chương trình được thiết kế theo kỹ thuật botom up. Đối tượng A Dữ liệu Các hàm Đối tượng B Dữ liệu Các hàm Đối tượng C Dữ liệu Các hàm Nguyễn Chí Trung 8 GIỚI THIỆU NGÔN NGỮ C++ Trong phần này: với mục đích so sánh ngôn ngữ C và C++ sẽ làm rõ một số đặc điểm mạnh của C++ so với C, đồng thời nhấn mạnh thêm hoặc giải thích chi tiết một số vấn đề quan trọng, thường gặp khi lập trình với C++. Chú thích trong C và trong C++ Trước hết C++ được phát triển từ C nên nó vẫn sử dụng lại tất cả các cú pháp ngôn ngữ như C và bổ sung thêm một số cú pháp mới. C++ đưa ra một kiểu chú thích mới để tiện chú thích trên một dòng nếu dùng ký pháp // và cũng tiện để viết trên nhiều dòng liên tục nếu dùng cặp ký pháp /* */ Chú thích trong C Chú thích trong C++ /* dong 1 chu thich cua C */ /* dong 2 chu thich cua C */ x=y=0; /*chu thich sau lenh */ /* Bat dau chu thich Dong 2 chu thich Ket thuc chu thich */ x=y=10; // chu thich sau lenh // co the chu thich tren 1 dong Các từ khóa mới C++ bổ sung vào C một số từ khóa mới asm friend new protected this catch operator inline virtual class public private cdecl pascal delete templete Phép chuyển kiểu bắt buộc Ngoài phép chuyển kiểu như trong ngôn ngữ C, C++ còn đưa ra phép chuyển kiểu mới. Xét ví dụ sau đây: int x=0; long z=(long)x; // chuyen kieu cua C long z=long(x); // chuyen kieu cua C++ Như vậy phép chuyển kiểu trong C++ có dạng như một hàm số chuyển kiểu đang được gọi. Cách chuyển kiểu này rõ ràng vừa khoa học vừa dễ d ọc. Khai báo biến Nhìn chung phạm vi hoạt động của biến phụ thuộc vào kiểu của biến và vị trí khai báo của biến trong chương trình. Nguyễn Chí Trung 9 Ngôn ngữ C đòi hỏi phải khai báo biến trước phạm vi mà các biến đang sử dụng. Cách khai báo đơn giản nhất trong C là khai báo biến toàn cục lên trước tất cả các hàm và khai báo biến cục bộ ở đầu thân từng hàm. Trong C++, khác với C, cho phép một cách khai báo biến mới, với cách khai báo này, một biến có thể khai báo ở vị trí bất kỳ miễn sao là trước khi sử dụng nó, phạm vi hoạt động của biến trong trường h ợp này là trong khối nơi biến đó được khai báo. Ví dụ 1.1 Khai báo sau đây trong C ++ chấp nhận nhưng trong C là lỗi vì C yêu cầu khai báo biến trước lệnh. clrscr(); int x; Ví dụ 1.2 void simple() { int n; // khai bao cuc bo for(int i=0;i<10;i++) // cho phep khai bao i trong for { int m; if (i&1) n+=1 } // su dung bien m ngoai pham vi khoi cua m nhu sau la sai m = n/2; // sai n = i; // dung } Hàm main Hàm main trong C không được định nghĩa kiểu. Hàm main trong C++ được định nghĩa kiểu để trả lại một giá trị nguyên cho hệ điều hành DOS, do đó phải khai báo là kiểu int, ngầm định-vì vậy sẽ là int. Tuy nhiên ta vẫn có thể định nghĩa kiểu void cho hàm main. Khi chương trình bắt đầu thực hiện, hàm main được gọi bởi một chương trình khởi động đặc biệt (start up code) có sẵn trong C++. Start up code trong C++ có bốn cách gọi (tùy chọn vào Option\ Application): Dos standard (t ệp C0.ASM) Dos overlays (tệp C0.ASM) Windows Application (tệp C0w.ASM) Windows DLL (tệp C0d.ASM) Giá trị trả lại của hàm main sẽ được Dos sử dụng để kiểm tra lỗi khi thực hiện chương trình. Giá trị này bằng 0 nếu không có lỗi. Các giá trị khác 0 được C++ biện luận theo các lỗi khi thực hiện chương trình. Nguyễn Chí Trung 10 Truyền tham số cho hàm Trước hết phải thống nhất về thuật ngữ: Lúc khai báo và định nghĩa hàm thì phần khai báo trong ngoặc đơn (nếu có) sau tên hàm gọi là tham số hình thức của hàm. Khi một hàm (có tham số hình thức) được gọi ra sử dụng thì chương trình gọi hàm phải truyền vào hàm các tham số thực sự để thay thế các tham số hình thức. Thuật ngữ "truyền tham số cho hàm" là có ý nói tới sự liên quan giữa hai việ c: việc khai báo, định nghĩa hàm với tham số hình thức và việc gọi hàm với tham số thực sự. Tuy nhiên, để cho ngắn gọn: tham số hình thức thường được gọi là đối và tham số thực sự nếu không nhầm lẫn với tham số hình thức vẫn thường được gọi tắt là tham số. C++ vẫn sử dụng hai cách truyền tham số cho hàm trong C. Đó là hai cách truyền tham số tương ứng v ới hai trường hợp:  Đối của hàm là biến thông thường, gọi là truyền tham số kiểu tham trị  Đối của hàm là biến con trỏ, gọi là truyền tham số kiểu con trỏ. Tuy nhiên, C++ có thêm một cách mới để truyền tham số cho hàm tương ứng với trường hợp đối của hàm là địa chỉ của biến. Cách truyền tham số như vậy gọi là truyền tham số kiểu tham chiếu . Cách mới này rất hay sử dụng vì thích hợp truyền tham số cho hàm là địa chỉ của đối tượng - một kiểu dữ liệu mới chỉ có trong C++ (kiểu lớp). Dưới đây ta nhắc lại hai cách truyền thống và cung cấp cách mới thứ ba. Truyền tham số kiểu tham trị Khi đối của hàm là biến đơn thuần thì khi gọi hàm, tham số được truyền vào hàm có thể là giá trị cụ thể (ví dụ 1.3) hoặc là một biến xác định (ví dụ 1.4) được khai báo trong chương trình gọi hàm. Về bản chất, theo cách truyền tham số vào hàm là biến thì chỉ có bản sao giá trị của biến được hàm sử dụng. Trong thân hàm, các bản sao này có thể bị thay đổi, từ đó suy ra, khi ra khỏi hàm thì giá trị ban đầu của biến truyề n vào hàm vẫn giữ nguyên. Chính vì đặc điểm trên nên ta gọi là "truyền tham số kiểu tham trị" . Ví dụ 1.3 #include <stdio.h> #include <conio.h> #define PI 3.1416 float S(float); main() { printf("\n dien tich h.tron ban kinh 50.0 la: %5.1f",S(50.0)); getch(); } float S(float r) {return Pi*r*r;} Trong ví dụ 1.3 ta thấy rằng S là một hàm có đối là biến bình thường kiểu float. Khi hàm main gọi S thì tham số có giá trị cụ thể bằng 50.0 được truyền vào hàm. [...]... gồm: Thông tin mô tả đối tượng (dữ liệu), gọi là trạng thái (status) của đối tượng Các hàm tác động lên đối tượng làm thay đổi trạng thái của đối tượng, gọi là phương thức (method) của đối tượng Dữ liệu và các hàm của đối tượng gắn liền với nhau để đặc tả đối tượng Đối tượng bao gồm cả sự vật, hiện tượng và các khái niệm Ví dụ: Đối tượng học sinh bao gồm các thông tin như họ tên, năm sinh, địa chỉ Các... cách biểu diễn những đặc tính chung nhất của các đối tượng có cùng một bản chất, bỏ qua những thông tin chi tiết của từng đối tượng riêng lẻ Trong lập trình, lớp được sử dụng như kiểu dữ liệu trừu tượng và nâng lên mức khuôn mẫu lớp Phương pháp lập trình hướng đối tượng bao gồm cả trừu tượng hoá dữ liệu và trừu tượng hoá chức năng Khai báo lớp các đối tượng Khai báo 27 Nguyễn Chí Trung class class_name... chương trình sử dụng các đối tượng cin và cout trong tệp tiêu đề iostream.h để nhập dữ liệu và in kết quả lên màn hình một mảng các phần tử có kiểu struct biểu thị thông tin cho một sinh viên gồm họ tên, năm sinh và điểm thi môn C++ 26 Nguyễn Chí Trung LỚP CÁC ĐỐI TƯỢNG LỚP CÁC ĐỐI TƯỢNG Các khái niệm cơ bản Khái niệm đối tượng (Object) Đối tượng là mô hình của thực thể, bao gồm: Thông tin mô tả đối tượng. .. là một đối tượng của lớp A và lệnh này gọi là lệnh tạo lập đối tượng Trừu tượng hoá dữ liệu và bao gói thông tin (Abstraction and Encapsulation) Việc đóng gói dữ liệu và các hàm gắn với nó vào một đơn vị cấu trúc tức là một lớp các đối tượng được xem như một nguyên tắc bao gói thông tin Nguyên tắc bao gói dữ liệu ngăn cấm sự truy nhập trực tiếp trong lập trình gọi là sự che dấu thông tin Trừu tượng. .. 1.1 Trình bầy các đặc trưng của lập trình hướng thủ tục và của lập trình hướng đối tượng Bài 1.2 Nếu ngay sau khi khai báo: float *p; float r; Thì lệnh nào sau đây đúng: (1) p = r; (2) p = &r; (3) *p = &r; (4) *p = r; Bài 1.3 Phân biệt hằng địa chỉ với biến con trỏ trong trường hợp xâu ký tự là một trong các kiến thức của C cần được củng cố Hãy xem xét và cho biết trong hai đoạn trình sau đây, đoạn trình. .. ba đối tượng a,b,c trong chương trình Mỗi khi một đối tượng mới được tạo, giá trị của biến static sẽ được xét tới Trong trường hợp này, giá trị của biến static là c lần lượt tăng đến 3 và dùng chung cho cả a,b,c Ngược lại với c, biến n không phải là biến static nên n có ba bản sao tương ứng với ba đối tượng khác nhau Nếu muốn sử dụng biến c làm biến đếm tổng số đối tượng và thể hiện thứ tự các đối tượng. .. phần riêng của nó và được bao bọc, che dấu Thành phần dữ liệu public của một đối tượng suy cho cùng cũng vẫn là sở hữu riêng của đối tượng, nhưng có thể được đối tượng đó thể hiện ra bên ngoài Một thành phần dữ liệu static được khai báo trong một lớp thì sẽ không là của riêng bất kỳ đối tượng nào trong lớp đó và tất cả các đối tượng của lớp sẽ dùng chung thành phần dữ liệu static này Về ý nghĩa, tác dụng:... thể đang xét) Về cách sử dụng: Khi đối tượng đầu tiên của lớp được tạo lập thì những biến static được tự khởi gán bằng 0 Vì thành phần static dùng chung cho tất cả các đối tượng của lớp nên không thể truy nhập thành phần static thông qua một đối tượng cụ thể nào trong lớp mà phải thông qua chính tên lớp cùng với toán tử phân giải miền xác định Trước khi sử dụng các đối tượng trong lớp phải có một lệnh... class_name { private: data_type var_name; return_type fun_name(arg_list); public: data_type var_name; return_type fun_name(arg_list); }; Tạo lập đối tượng Tạo lập đối tượng ngay sau khi khai báo class class_name { // Các thành phần của lớp } obj_name; Tạo lập đối tượng bên ngoài lớp class class_name obj_name; Phạm vi hoạt động của các thành phần bên trong lớp Vùng private Data function Data function... của học sinh trước hết phải kể đến các hàm nhập dữ liệu, xem dữ liệu Đối tượng hình chữ nhật bao gồm hai kích thước dài và rộng và các hàm liên quan đến một hình chữ nhật thường là hàm tính chu vi và diện tích của nó Lớp đối tượng (Class) Các đối tượng có cùng thành phần dữ liệu và phương thức hình thành lên một lớp Vậy có thể xem đối tượng là một thể hiện (instance) của lớp Lớp là kiểu dữ liệu được định

Ngày đăng: 27/03/2014, 12:49

Tài liệu cùng người dùng

Tài liệu liên quan