Giáo trình Lập trình hướng đối tượng - Nghề: Lập trình viên máy tính - Trình độ: Cao đẳng - Trường Cao đẳng nghề kỹ thuật công nghệ

pdf 94 trang Gia Huy 17/05/2022 2064
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Lập trình hướng đối tượng - Nghề: Lập trình viên máy tính - Trình độ: Cao đẳng - Trường Cao đẳng nghề kỹ thuật công nghệ", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_huong_doi_tuong_nghe_lap_trinh_vien_may.pdf

Nội dung text: Giáo trình Lập trình hướng đối tượng - Nghề: Lập trình viên máy tính - Trình độ: Cao đẳng - Trường Cao đẳng nghề kỹ thuật công nghệ

  1. BỘ LAO ĐỘNG - THƯƠNG BINH VÀ XÃ HỘI TRƯỜNG CAO ĐẲNG NGHỀ KỸ THUẬT CÔNG NGHỆ š›&š› GIÁO TRÌNH MÔ ĐUN :LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG NGHỀ: LẬP TRÌNH VIÊN MÁY TÍNH TRÌNH ĐỘ: CAO ĐẲNG Ban hành kèm theo Quyết định số: 13A/QĐ-CĐNKTCN ngày 10 tháng 01 năm 2019 của Hiệu trưởng Trường Cao đẳng nghề Kỹ thuật Công nghệ Hà Nội, năm 2021 (Lưu hành nội bộ) 1
  2. TUYÊN BỐ BẢN QUYỀN: Tài liệu này thuộc loại sách giáo trình nên các nguồn thông tin có thể được phép dùng nguyên bản hoặc trích dùng cho các mục đích về đào tạo và tham khảo. Mọi mục đích khác mang tính lệch lạc hoặc sử dụng với mục đích kinh doanh thiếu lành mạnh sẽ bị nghiêm cấm. MÃ TÀI LIỆU : MĐLTV 21 2
  3. LỜI GIỚI THIỆU C++ là ngôn ngữ lập trình hướng đối tượng được mở rộng từ ngôn ngữ C. Do vậy, C++ có ưuđiểm là kế thừa được các điểm mạnh truyền thống của ngôn ngữ C như uyển chuyển, tương thíchvới các thiết bị phần cứng. Hiện nay, C++ là một ngôn ngữ lập trình phổ biến, được giảng dạy tạicác trường đại học trong nước và trên thế giới và đặc biệt được sử dụng rộng rãi cho nhu cầu pháttriển của công nghiệp phần mềm hiện nay. Tài liệu này không những nhằm giới thiệu cho sinh viên ngôn ngữ lập trình C++, mà còn mong muốn qua đó sinh viên có thể hiểu được tư tưởng củaphương pháp lập trình hướng đối tượng nói chung. Nội dung của tài liệu bao gồm hai phần chính: • Phần thứ nhất là lập trình nâng cao với C++, bao gồm lập trình C++ với con trỏ và mảng, các kiểu dữ liệu có cấu trúc cùng các thao tác vào ra trên tệp. • Phần thứ hai là lập trình hướng đối tượng với C++, bao gồm các định nghĩa và các thao tác trên lớp đối tượng, tính kế thừa và tương ứng bội trong C++, cách sử dụng một số lớp cơ bản trong thư viện C++. Mặc dù có rất nhiều cố gắng, nhưng không tránh khỏi những sai sót, rất mong nhận được sự đóng góp ý kiến của độc giả để giáo trình được hoàn thiện hơn. Xin chân thành cảm ơn! Hà Nội, ngày 23 tháng 04 năm 2021 Tham gia biên soạn 1. Chủ biên Trần Thị Vinh 2. Tập thể Giảng viên Khoa CNTT Mọi thông tin đóng góp chia sẻ xin gửi về hòm thư tranthivinhvnn@gmail.com hoặc liên hệ số điện thoại 0978113529 3
  4. MỤC LỤC LỜI GIỚI THIỆU 3 MỤC LỤC 4 BÀI 1: TỔNG QUAN VỀ LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG 11 1. Lịch sử phát triển 11 2. Khái niệm về lập trình hướng đối tượng và các đặc trưng 11 3. Một số khái niệm cơ bản 11 3.1. Lớp, đối tượng 11 3.2. Trừu tượng hóa 12 3.3. Thông điệp, đóng gói, che dấu thông tin. 12 3.4. Kế thừa 13 3.5. Đa hình 13 4. Phân tích bài toán theo tiếp cận hướng đối tượng 13 5. Ngôn ngữ lập trình hướng đối tượng 16 BÀI 2: LỚP VÀ ĐỐI TƯỢNG 19 1. Định danh 19 1.1 Quy định với định danh 19 1.2.Quy ước với định danh 20 2.1. Kiểu dữ liệu nguyên thủy 21 2.2.Giá trị hằng 23 2.3.Chuyển đổi kiểu dữ liệu 23 2.4.Khai báo và khởi tạo biến, hằng 24 3. Toán tử 25 3.1.Toán tử số học 25 Toán tử số học trong C++ 25 3.2. Toán tử bit 25 3.3.Toán tử quan hệ 26 3.4. Toán tử logic 27 3.5. Toán tử gán 27 4. Nhập và hiển thị dữ liệu lên màn hình 29 4.1 Hiển thị dữ liệu lên màn hình 29 4
  5. 4.2 Nhập dữ liệu từ bàn phím 29 5. Cấu trúc điều khiển 30 5.1. Lệnh if-else 30 5.2. Lệnh switch-case 30 5.3. Vòng lặp while và do while 33 5.4.Vòng lặp for 34 5.5.Các lệnh làm thay đổi cấu trúc lập trình 34 5.6.Phạm vi biến 34 6.Mảng một chiều 35 6.1.Khai báo và khởi tạo mảng 35 6.2.Một số thao tác với mảng một chiều 35 7.Lập trình với cấu trúc lặp và các thao tác với mảng trong Java 36 BÀI 3: ĐÓNG GÓI VÀ XÂY DỰNG LỚP, TẠO VÀ SỬ DỤNG 38 1.Trừu tượng hóa dữ liệu 38 1.1.Trừu tượng hóa dữ liệu là gì? 38 1.2.Trừu tượng hóa dữ liệu là gì? 38 1.3.So sánh đối tượng và lớp 39 2. Đóng gói và xây dựng lớp 40 2.1. Đóng gói là gì? 40 2.2. Xây dựng lớp 40 2.3. Che giấu dữ liệu 41 2.4. Phương thức set/get 41 3. Tạo và sử dụng đối tượng 41 3.1. Khởi tạo dữ liệu 41 3.2.Phương thức khởi tạo 41 3.3.Khai báo và khởi tạo đối tượng 41 3.4.Sử dụng đối tượng 41 4. Từ khóa this 43 5. Truyền tham số cho phương thức 44 5.1. Truyền tham số kiểu dữ liệu tham trị 44 5.2. Truyền tham số kiểu dữ liệu tham chiếu 44 6. Chồng phương thức 45 7. Xây dựng lớp đơn giản, tạo và sử dụng các đối tượng 46 5
  6. 8. Lớp String, StringBuilder, StringBuffer. 55 BÀI 4: TỔNG QUAN VỀ JDBC 59 1. Tổng quan về JDBC 59 2. Cài đặt JDBC 59 3. Kết nối cơ sở dữ liệu 60 4. Tạo ứng dụng JDBC 61 BÀI 5: KẾ THỪA 64 1. Một số khái niệm cơ bản 64 1.1 Tổng quát hóa và đặc biệt hóa 64 1.2. Tính kế thừa 64 1.3. Lớp cơ sở, lớp dẫn xuất 64 1.4. Các dạng kế thừa 66 1.4.1. Đơn kế thừa 66 1.4.2. Đa kế thừa 66 2. Các hình thức kế thừa 68 2.1. Hình thức kế thừa private 68 Kiểu kế thừa trong C++ 68 2.2. Hình thức kế thừa Protected 68 2.3. Hình thức kế thừa Public 68 3. Sự trùng tên trong kế thừa 68 4. Lớp cơ sở ảo và lớp cơ sở trừu tượng 70 BÀI 6: ĐA HÌNH VÀ GIAO DIỆN 73 1. Nạp chồng hàm, nạp chồng toán tử 73 2. Đa hình 74 2.1. Khái niệm 74 2.2. Vai trò 74 2.3. Xây dựng ứng dụng sử dụng tính chất đa hình 74 3. Giao diện (Interface) 75 3.1. Khái niệm 75 3.2. Cách khai báo và xây dựng giao diện trong C# 75 BÀI 7: LẬP TRÌNH ANDROID CƠ BẢN 80 1.Cài đặt Android Studio 80 2.Viết ứng dụng cơ bản: Nhập/Hiển thị, khai báo biến, 87 6
  7. 3.Lập trình hướng đối tượng trong Android 88 4.Tạo và sử dụng lớp trong Android 89 5.Bắt sự kiện Onclick 90 6.Tùy chỉnh Layout 90 7.Tạo hàm con 90 8.Chèn hình ảnh ImageView, gán hình nền cho đối tượng 90 9.Sử dụng đối tượng CountDownTimer 91 10.Sử dụng ASYNC 91 11.Đọc file từ internet 92 12.Đọc XML & RSS 92 13.Tạo diễn hoạt hình với Animation 92 7
  8. GIÁO TRÌNH MÔ ĐUN Tên mô đun: Lập trình hướng đối tượng Mã mô đun: MĐLTV 21 Vị trí, tính chất, ý nghĩa và vai trò của mô đun : - Vị trí: Là mô đun chuyên ngành. Mô đun có thể được bố trí học khi đã học xong các môn học cơ sở ngành như: Cơ sở dữ liệu, Ngôn ngữ lập trình C/C++, Cấu trúc dữ liệu và giải thuật. - Tính chất: Là mô đun cung cấp các khái niệm, đặc trưng cơ bản của lập trình hướng đối tượng như: đối tượng, lớp đối tượng, phương thức, thuộc tính, nạp chồng, kế thừa, đóng gói, trừu tượng, đa hình, Ngoài ra, học phần còn cung cấp cách thức giải quyết bài toán theo tư duy hướng đối tượng. Mục tiêu của mô đun: - Về kiến thức + Trình bày được các khái niệm và các thành phần cơ bản của lập trình hướng đối tượng. + Phân tích được bài toán theo tư duy hướng đối tượng + Xác định được các đối tượng và lớp đối tượng trong các bài toán cụ thể - Về kỹ năng + Thiết kế và xây dựng được lớp đối tượng bằng ngôn ngữ lập trình cụ thể + Lập trình giải quyết được bài toán thực tế ở mức đơn giản bằng ngôn ngữ lập trình hướng đối tượng. Tích cực ứng dụng lập trình trực quan cho các ứng dụng trong thực tế. - Về năng lực tự chủ và trách nhiệm: + Khả năng tìm tài liệu, đọc hiểu tài liệu + Khả năng làm việc nhóm Nội dung của mô đun: Thời gian Số Tên các bài trong mô đun Tổng Lý Thực Kiểm TT số thuyết hành tra* 1 Bài 1: Tổng quan về lập trình hướng đối tượng 1. Lịch sử phát triển 2. Khái niệm về lập trình hướng đối tượng và các đặc trưng 15 5 10 3. Một số khái niệm cơ bản 4. Phân tích bài toán theo tiếp cận hướng đối tượng 5. Ngôn ngữ lập trình hướng đối tượng 2 Bài 2: Lớp- Đối tượng 25 7 17 1 8
  9. 1. Định nghĩa Lớp đối tượng 2. Phạm vi Private, Public, Protected 3. Mảng đối tượng 4. Phương thức khởi tạo và phương thức hủy bỏ 5. Con trỏ this 3 Bài 3: Đóng gói và xây dựng lớp; tạo và sử dụng đối tượng 1. Trừu tượng hóa dữ liệu 2. Đóng gói và xây dựng lớp 3. Tạo và sử dụng đối tượng 4. Từ khóa this 20 5 14 1 5. Truyền tham số cho phương thức 6. Chồng phương thức 7. Xây dựng lớp đơn giản, tạo và sử dụng các đối tượng 8. Lớp String, StringBuilder, StringBuffer. 4 Bài 4: Tổng quan về JDBC 13 2 11 1. Tổng quan về JDBC 2. Cài đặt JDBC 3. Kết nối Cơ sở dữ liệu 4. Tạo ứng dụng JDBC cơ bản 5 Bài5: Kế thừa 15 6 8 1 1. Một số khái niệm cơ bản 2. Các hình thức kế thừa 3. Sự trùng tên trong kế thừa 4. Lớp cơ sở ảo và lớp cơ sở trừu tượng 6 Bài 6: Đa hình và Giao diện 15 3 12 1. Nạp chồng hàm, nạp chồng toán tử 2. Đa hình 3. Giao diện (Interface) 7 Bài 7: Lập trình Android cơ bản 1.Cài đặt Android Studio 2.Viết ứng dụng cơ bản: Nhập/Hiển thị, khai báo biến, 3.Lập trình hướng đối tượng trong Android 15 0 15 4.Tạo và sử dụng lớp trong Android 5.Bắt sự kiện Onclick 6.Tùy chỉnh Layout 7.Tạo hàm con 8.Chèn hình ảnh ImageView, gán hình nền 9
  10. cho đối tượng 9.Sử dụng đối tượng CountDownTimer 10.Sử dụng ASYNC 11.Đọc file từ internet 12.Đọc XML & RSS 13.Tạo diễn hoạt hình với Animation Thi kết thúc mô đun 2 1 1 Cộng 120 28 88 4 * Ghi chú: Thời gian kiểm tra lý thuyết được tính vào gìơ lý thuyết, Thời gian kiểm tra thực hành được tính vào giờ thực hành. 2. Nội dung chi tiết: 10
  11. BÀI 1: TỔNG QUAN VỀ LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG Mã bài: MĐLTV 21.01 Giới thiệu: Trong lập trình hướng cấu trúc, chương trình chính được chia nhỏ thành các chương trình con và mỗi chương trình con thực hiện một công việc xác định. Chương trình chính sẽ gọi đến chương trình con theo một giải thuật, hoặc một cấu trúc được xác định trong chương trình chính. Các ngôn ngữ lập trình cấu trúc phổ biến là Pascal, C và C++. Riêng C++ ngoài việc có đặc trưng của lập trình cấu trúc do kế thừa từ C, còn có đặc trưng của lập trình hướng đối tượng. Cho nên C++ còn được gọi là ngôn ngữ lập trình nửa cấu trúc, nửa hướng đối tượng. Mục tiêu: - Trình bày được khái niệm và các đặc trưng của lập trình hướng đối tượng. - Thực hiện được các thao tác cơ bản trên môi trường lập trình cụ thể. - So sánh được đặc trưng của lập trình hướng đối tượng với một số phương pháp lập trình đã học. - Nhận dạng được các khái niệm đối tượng tron lập trình hướng đối tượng - Sử dụng được các lệnh cơ bản trong ngôn ngữ lập trình hướng đối tượng cụ thể. Nội dung chính: 1. Lịch sử phát triển Trong lập trình hướng đối tượng: • Người ta coi các thực thể trong chương trình là các đối tượng và sau đó trừu tượng hoá đối tượng thành lớp đối tượng. • Dữ liệu được tổ chức thành các thuộc tính của lớp. Nguời ta ngăn chặn việc thay đổi tuỳ tiện dữ liệu trong chương trình bằng các cách giới hạn truy nhập như chỉ cho phép truy nhập dữ liệu thông qua đối tượng, thông qua các phương thức mà đối tượng được cung cấp • Quan hệ giữa các đối tượng là quan hệ ngang hàng hoặc quan hệ kế thừa: Nếu lớp B kế thừa từ lớp A thì A được gọi là lớp cơ sở và B được gọi là lớp dẫn xuất. 2. Khái niệm về lập trình hướng đối tượng và các đặc trưng Đặc trưng cơ bản nhất của lập trình cấu trúc thể hiện ở mối quan hệ: chương trình = Cấu trúc dữ liệu + Giải thuật Trong đó: • Cấu trúc dữ liệu là cách tổ chức dữ liệu cho việc xử lý bởi một hay nhiều chương trình nào đó. • Giải thuật là một quy trình để thực hiện một công việc xác định Trong chương trình, giải thuật có quan hệ phụ thuộc vào cấu trúc dữ liệu: • Một cấu trúc dữ liệu chỉ phù hợp với một số hạn chế các giải thuật. • Nếu thay đổi cấu trúc dữ liệu thì phải thay đổi giải thuật cho phù hợp. • Một giải thuật thường phải đi kèm với một cấu trúc dữ liệu nhất định. 3. Một số khái niệm cơ bản 3.1. Lớp, đối tượng Đối tượng (Object) Trong lập trình hướng đối tượng, đối tượng được coi là đơn vị cơ bản nhỏ nhất. Các dữ diệu và 11
  12. cách xử lí chỉ là thành phần của đối tượng mà không được coi là thực thể. Một đối tượng chứa các dữ liệu của riêng nó, đồng thời có các phương thức (hành động) thao tác trên các dữ liệu đó: Đối tượng = dữ liệu + phương thức Lớp (Class) Khi có nhiều đối tượng giống nhau về mặt dữ liệu và phương thức, chúng được nhóm lại với nhau và gọi chung là lớp: • Lớp là sự trừu tượng hoá của đối tượng • Đối tượng là một thể hiện của lớp. 3.2. Trừu tượng hóa Trừu tượng hóa dữ liệu (Data abstraction) liên quan tới việc chỉ cung cấp thông tin cần thiết tới bên ngoài và ẩn chi tiết cơ sở của chúng, ví dụ: để biểu diễn thông tin cần thiết trong chương trình mà không hiển thị chi tiết về chúng. Trừu tượng hóa dữ liệu (Data abstraction) là một kỹ thuật lập trình mà dựa trên sự phân biệt của Interface và Implementation (trình triển khai). Xem xét ví dụ về một chiếc TV, bạn có thể bật/tắt, thay đổi kênh, chỉnh âm lượng, và thêm các thiết bị ngoại vi như loa, VCR và DVD. Nhưng bạn không biết các chi tiết nội vi của nó, đó là, bạn không biết cách nó nhận tín hiệu qua không khí hoặc qua dây cáp, cách phiên dịch chúng và cuối cùng là hiển thị chúng trên màn hình. Vì thế, có thể nói rằng một chiếc TV phân biệt rõ ràng trình triển khai nội vi của nó với giao diện ngoại vi và bạn có thể thao tác với interface với các nút nguồn, điều khiển âm lượng mà không cần có bất kỳ hiểu biết về những gì diễn ra bên trong nó. Bây giờ, về mặt ngôn ngữ lập trình C++, thì các lớp C++ cung cấp Trừu tượng hóa dữ liệu (Data abstraction) ở mức thật tuyệt vời. Chúng cung cấp đủ các phương thức public tới bên ngoài để thao tác với tính năng của đối tượng và để thao tác dữ liệu đối tượng, ví dụ: trạng thái mà không cần thực sự biết về cách lớp đó đã được triển khai nội tại. Ví dụ, chương trình của bạn có thể tạo một lời gọi tới hàm sort() mà không cần biết về hàm đó thực sự sử dụng thuật toán gì để sắp xếp các giá trị đã cho. Thực ra, trình triển khai cơ sở (underlying implementation) của tính năng sắp xếp có thể thay đổi tùy vào thư viện, và miễn là Interface vẫn như cũ thì lời gọi hàm của bạn vẫn tiếp tục làm việc. 3.3. Thông điệp, đóng gói, che dấu thông tin. Đóng gói dữ liệu (Encapsulation) • Các dữ liệu được đóng gói vào trong đối tượng. Mỗi dữ liệu có một phạm vi truy nhập riêng. • Không thể truy nhập đến dữ liệu một cách tự do như lập trình cấu trúc • Muốn truy nhập đến các dữ liệu đã được bảo vệ, phải thông qua các đối tượng, nghĩa là phải sử dụng các phương thức mà đối tượng cung cấp mới có thể truy nhập đến dữ liệu của đối tượng đó. Tuy nhiên, vì C++ chỉ là ngôn ngữ lập trình nửa đối tượng, cho nên C++ vẫn cho phép định nghĩa các biến dữ liệu và các hàm tự do, đây là kết quả kế thừa từ ngôn ngữ C, một ngôn ngữ lập trình thuần cấu trúc. 12
  13. 3.4. Kế thừa Kế thừa (Inheritance) Tính kế thừa của lập trình hướng đối tượng cho phép một lớp có thể kế thừa từ một số lớp đã tồn tại. Khi đó, lớp mới có thể sử dụng dữ liệu và phương thức của các lớp cơ sở như là của mình. Ngoài ra, lớp dẫn xuất còn có thể bổ sung thêm một số dữ liệu và phương thức. Ưu điểm của kế thừa là khi thay đổi dữ liệu của một lớp, chỉ cần thay đổi các phương thức trong phạm vi lớp cơ sở mà không cần thay đổi trong các lớp dẫn xuất. 3.5. Đa hình Đa hình (Polymorphsim) Đa hình là khái niệm luôn đi kèm với kế thừa. Do tính kế thừa, một lớp có thể sử dụng lại các phương thức của lớp khác. Tuy nhiên, nếu cần thiết, lớp dẫn xuất cũng có thể định nghĩa lại một số phương thức của lớp cơ sở. Đó là sự nạp chồng phương thức trong kế thừa. Nhờ sự nạp chồng phương thức này, ta chỉ cần gọi tên phương thức bị nạp chồng từ đối tượng mà không cần quan tâm đó là đối tượng của lớp nào. Chương trình sẽ tự động kiểm tra xem đối tượng là thuộc kiểu lớp cơ sở hay thuộc lớp dẫn xuất, sau đó sẽ gọi phương thức tương ứng với lớp đó. Đó là tính đa hình. 4. Phân tích bài toán theo tiếp cận hướng đối tượng Phương pháp lập trình hướng đối tượng Xuất phát từ hai hạn chế chính của phương pháp lập trình cấu trúc: Không quản lí được sự thay đổi dữ liệu khi có nhiều chương trình cùng thay đổi một biến chung. Vấn đề này đặc biệt nghiêm trọng khi các ứng dụng ngày càng lớn, người ta không thể kiểm soát được sự truy nhập đến các biến dữ liệu chung. Không tiết kiệm được tài nguyên con người: Giải thuật gắn liền với cấu trúc dữ liệu, nếu thay đổi cấu trúc dữ liệu, sẽ phải thay đổi giải thuật, và do đó, phải viết lại mã chương trình từ đầu. Để khắc phục được hai hạn chế này khi giải quyết các bài toán lớn, người ta xây dựng một phương pháp tiếp cận mới, là phương pháp lập trình hướng đối tượng, với hai mục đích chính: • Đóng gói dữ liệu để hạn chế sự truy nhập tự do vào dữ liệu, không quản lí được. • Cho phép sử dụng lại mã nguồn, hạn chế việc phải viết lại mã từ đầu cho các chương trình. Việc đóng gói dữ liệu được thực hiện theo phương pháp trừu tượng hoá đối tượng thành lớp từ thấp lên cao như sau: • Thu thập các thuộc tính của mỗi đối tượng, gắn các thuộc tính vào đối tượng tương ứng. 13
  14. • Nhóm các đối tượng có các thuộc tính tương tự nhau thành nhóm, loại bỏ bớt các thuộc tính cá biệt, chỉ giữ lại các thuộc tính chung nhất. Đây được gọi là quá trình trừu tượng hoá đối tượng thành lớp. • Đóng gói dữ liệu của các đối tượng vào lớp tương ứng.Mỗi thuộc tính của đối tượng trở thành một thuộc tính của lớp tương ứng. • Việc truy nhập dữ liệu được thực hiện thông qua các phương thức được trang bị cho lớp. Không được truy nhập tự do trực tiếp đến dữ liệu. • Khi có thay đổi trong dữ liệu của đối tượng, ta chỉ cần thay đổi các phương thức truy nhập thuộc tính của lớp, mà không cần phải thay đổi mã nguồn của các chương trình sử dụng lớp tương ứng. Việc cho phép sử dụng lại mã nguồn được thực hiện thông qua cơ chế kế thừa trong lập trình hướng đối tượng. Theo đó: • Các lớp có thể được kế thừa nhau để tận dụng các thuộc tính, các phương thức của nhau. • Trong lớp dẫn xuất (lớp được kế thừa) có thể sử dụng lại các phương thức của lớp cơ sở (lớp bị lớp khác kế thừa) mà không cần thiết phải cài đặt lại mã nguồn. • Ngay cả khi lớp dẫn xuất định nghĩa lại các phương thức cho mình, lớp cơ sở cũng không bị ảnh hưởng và không phải sửa lại bất kì một đoạn mã nguồn nào. Ngôn ngữ lập trình hướng đối tượng phổ biến hiện nay là Java và C++.Tuy nhiên, C++ mặc dù cũng có những đặc trưng cơ bản của lập trình hướng đối tượng nhưng vẫn không phải là ngôn ngữ lập trình thuần hướng đối tượng.Java thật sự là một ngôn ngữ lập trình thuần hướng đối tượng. Đặc trưng Lập trình hướng đối tượng có hai đặc trưng cơ bản: • Đóng gói dữ liệu: dữ liệu luôn được tổ chức thành các thuộc tính của lớp đối tượng.Việc truy nhập đến dữ liệu phải thông qua các phương thức của đối tượng lớp. • Sử dụng lại mã nguồn: việc sử dụng lại mã nguồn được thể hiện thông qua cơ chế kế thừa. Cơ chế này cho phép các lớp đối tượng có thể kế thừa từ các lớp đối tượng khác.Khiđó, trong các lớp kế thừa, có thể sử dụng các phương thức (mã nguồn) của các lớp bị kế thừa, mà không cần phải định nghĩa lại. Ưu điểm Lập trình hướng đối tượng có một số ưu điểm nổi bật: • Không còn nguy cơ dữ liệu bị thay đổi tự do trong chương trình. Vì dữ liệu đã được đóng gói vào các đối tượng.Nếu muốn truy nhập vào dữ liệu phải thông qua các phương thức cho phép của đối tượng. • Khi thay đổi cấu trúc dữ liệu của một đối tượng, không cần thay đổi các đổi mã nguồn của các đối tượng khác, mà chỉ cần thay đổi một số hàm thành phần của đối tượng bị thay đổi. Điều này hạn chế sự ảnh hưởng xấu của việc thay đổi dữ liệu đến các đối tượng khác trong chương trình. • Có thể sử dụng lại mã nguồn, tiết kiệm tài nguyên. Vì nguyên tắc kế thừa cho phép các lớp kế thừa sử dụng các phương thức được kế thừa từ lớp khác như những phương thức của chính nó, mà không cần thiết phải định nghĩa lại. • Phù hợp với các dự án phần mềm lớn, phức tạp. Phương pháp phân tích và thiết kế hướng đối tượng: 14
  15. Một vấn đề cơ bản đặt ra cho phương pháp hướng đối tượng là từ một bài toán ban đầu, làm sao để thu được một tập các đối tượng, với các chức năng được phối hợp với nhau, đáp ứng được yêu cầu của bài toán đặt ra? Phương pháp phân tích thiết kế hướng đối tượng ra đời nhằm trả lời cho câu hỏi này. Mục đích là xây dựng một tập các lớp đối tượng tương ứng với mỗi bài toán, phương pháp này tiến hành theo hai pha chính: Pha phân tích: Chuyển đổi yêu cầu bài toán từ ngôn ngữ tự nhiên sang ngôn ngữ mô hình. Pha thiết kế: Chuyển đổi đặc tả bài toán dưới dạng ngôn ngữ mô hình sang một mô hình cụ thể có thể cài đặt được. Hai pha phân tích và thiết kế này bao gồm nhiều bước khác nhau(gồm 6 bước): • Mô tả bài toán • Đặc tả yêu cầu • Trích chọn đối tượng • Mô hình hoá lớp đối tượng • Thiết kế tổng quan • Thiết kế chi tiết. Bước 1: Mô tả bài toán Bài toán ban đầu được phát biểu dưới dạng ngôn ngữ tự nhiên, bao gồm: • Mục đích, chức năng chung • Các yêu cầu về thông tin dữ liệu • Các yêu cầu về chức năng thực hiện Bước 2: Đặc tả yêu cầu Các yêu cầu được hình thức hoá lên một mức cao hơn bằng cách sử dụng ngôn ngữ kiểu kịch bản(scenario) để mô tả. Trong một kịch bản, mỗi chức năng, mỗi hoạt động được mô tả bằng một kịch bản, bao gồm: • Các tác nhân tham gia vào kịch bản. • Vai trò của mỗi tác nhân trong kịch bản. • Thứ tự các hành động mà mỗi tác nhân thực hiện: khi nào thực hiện, tác động vào tác nhân nào, thông tin nào được trao đổi. Quá trình trên được tiến hành với tất cả các chức năng yêu cầu của hệ thống. Bước 3: Trích chọn đối tượng Bước này sẽ tiến hành đề xuất các đối tượng có thể có mặt trong hệ thống: • Dựa vào các kịch bản được mô tả trong bước hai, chọn ra các tác nhân có xuất hiện để đề xuất thành các đối tượng. • Lựa chọn các đối tượng bằng cách loại bỏ các tác nhân bên ngoài hệ thống, các tác nhân trùng lặp. • Cuối cùng, ta thu được tập các đối tượng của hệ thống. Bước 4: Mô hình hoá lớp đối tượng Bước này tiến hành trừu tượng hoá đối tượng thành các lớp: • Thu thập tất cả các thuộc tính của mỗi đối tương vừa thu thập được, dựa vào yêu cầu về thông tin trong yêu cầu hệ thống (từ bước 1). • Thu thập các hành động mà mỗi đối tượng cần thực hiện, dựa vào các kịch bản mà đối tượng tương ứng có tham gia (trong bước 2). • Nhóm các đối tượng tương tự nhau, hoặc có nhiều thuộc tính gần giống nhau. • Loại bỏ một số thuộc tính cá biệt, riêng tư của một số đối tượng trong nhóm. 15
  16. • Mô hình mỗi nhóm đối tượng còn lại thành lớp: Các thuộc tính chung của các đối tượng thành thuộc tính của lớp, các hành động của các đối tượng thành phương thức của lớp. Kết quả thu được một tập các lớp đối tượng ban đầu của hệ thống. Bước 5: Thiết kế tổng quát Bước này sẽ tiến hành thiết kế vĩ mô, nghĩa là thiết kế mối quan hệ giữa các lớp trong hệ thống: • Xác định sơ đồ thừa kế, nếu có, giữa các lớp: Nếu hai lớp có một số thuộc tính chung, thì tách các thuộc tính chung làm thành một lớp cơ sở, và hai lớp ban đầu đều dẫn xuất từ lớp cơ sở đó. Thông thường, lớp các trừu tượng (chung nhất) sẽ làm lớp cơ sở, lớp càng cụ thể, càng chi tiết thì làm lớp dẫn xuất (lớp con, cháu). • Xác định tương tác, nếu có, giữa các lớp: Dựa vào các kịch bản được mô tả trong bước 2, hai tác nhân có tương tác với nhau thì hai lớp tương ứng ở bước này cũng có tương tác với nhau. Kết quả thu được của bước này là một sơ đồ quan hệ bên ngoài giữa các lớp trong hệ thống. Bước 6: Thiết kế chi tiết Bước này sẽ thực hiện thiết kế ở mức vi mô, nghĩa là thiết kế kiến trúc bên trong của mỗi lớp đối tượng: • Tổ chức dữ liệu của lớp theo các thuộc tính. Qui định phạm vi truy nhập cho từng thuộc tính. • Thiết kế chi tiết cách cư xử của lớp đối tượng thông qua các phương thức của lớp: Xác định kiểu dữ liệu trả về, kiểu tham số của phương thức, mô tả thuật toán chi tiết cho từng phương thức, nếu cần. Kết quả thu được của bước này là một tập các lớp với thiết kế chi tiết kiến trúc bên trong. Sau các bước phân tích thiết kế hướng đối tượng từ một yêu cầu của bài toán ban đầu, ta thu được một mô hình hệ thống hướng đối tượng chi tiết: • Có cái nhìn tổng quan, vĩ mô về hệ thống bằng mô hình thiết kế tổng quan, chỉ rõ số lượng các lớp đối tượng, mối quan hệ kế thừa và quan hệ tương tác giữa các lớp đối tượng trong hệ thống. • Có cái nhìn chi tiết, vi mô về hệ thống bằng mô hình thiết kế chi tiết. Mô hình này chỉ rõ bên trong mỗi lớp đối tương: các thuộc tính, các phương thức với kiểu trả về và kiểu tham số, thuật toán chi tiết cho mỗi phương thức. Sau pha phân tích và thiết kế hướng đối tượng, ta thu được đặc tả hệ thống dưới dạng mô hình các lớp: quan hệ giữa các lớp và kiến trúc bên trong của mỗi lớp. Đây sẽ là đầu vào cho pha tiếp theo, pha lập trình hướng đối tượng, như chúng ta đã biết. 5. Ngôn ngữ lập trình hướng đối tượng Đặc trưng Lập trình hướng đối tượng có hai đặc trưng cơ bản: • Đóng gói dữ liệu: dữ liệu luôn được tổ chức thành các thuộc tính của lớp đối tượng. Việc truy nhập đến dữ liệu phải thông qua các phương thức của đối tượng lớp. • Sử dụng lại mã nguồn: việc sử dụng lại mã nguồn được thể hiện thông qua cơ chế kế thừa. Cơ chế này cho phép các lớp đối tượng có thể kế thừa từ các lớp đối tượng khác. Khi 16
  17. đó, trong các lớp dẫn xuất, có thể sử dụng các phương thức (mã nguồn) của các lớp cơ sở mà không cần phải định nghĩa lại. Ưu điểm Lập trình hướng đối tượng có một số ưu điểm nổi bật: • Không còn nguy cơ dữ liệu bị thay đổi tự do trong chương trình. Vì dữ liệu đã được đóng gói vào các đối tượng. Nếu muốn truy nhập vào dữ liệu phải thông qua các phương thức được cho phép của đối tượng. • Khi thay đổi cấu trúc dữ liệu của một đối tượng, không cần thay đổi mã nguồn của các đối tượng khác, mà chỉ cần thay đổi một số thành phần của đối tượng dẫn xuất. Điều này hạn chế sự ảnh hưởng xấu của việc thay đổi dữ liệu đến các đối tượng khác trong chương trình. • Có thể sử dụng lại mã nguồn, tiết kiệm tài nguyên, chi phí thời gian. Vì nguyên tắc kế thừa cho phép các lớp dẫn xuất sử dụng các phương thức từ lớp cơ sở như những phương thức của chính nó, mà không cần thiết phải định nghĩa lại. • Phù hợp với các dự án phần mềm lớn, phức tạp. 17
  18. Bài tập thực hành Hãy phân tích bài toán sau theo hướng tiếp cận đối tượng Xây dựng lớp Color gồm: Thuộc tính: TenMau, MaMau Phương thức: 〈 Cấu tử không tham số 〈 Cấu tử có tham số 〈 Hủy 〈 Nạp chồng toán tử nhập 〈 Nạp chồng toán tử xuất 〈 getTenMau() : hàm trả về TenMau Xây dựng lớp Point gồm: Thuộc tính: int x, y Phương thức: 〈 Cấu tử không tham số 〈 Cấu tử có tham số 〈 Hủy 〈 Nạp chồng toán tử nhập 〈 Nạp chồng toán tử xuất 〈 CheoChinh : hàm kiểm tra Point có thuộc đường chéo chính hay không (1 điểm thuộc đường chéo chính khi và chỉ khi tung độ bằng hoành độ). Xây dựng lớp Pixel kế thừa từ lớp Color và Point bao gồm thêm: Phương thức: 〈 Cấu tử không tham số 〈 Cấu tử có tham số 〈 Nạp chồng toán tử nhập 〈 Nạp chồng toán tử xuất 〈 KiemTra: hàm kiểm tra Pixel thuộc đường chéo chính và có màu “Xanh” hay không? Chương trình chính: Nhập vào từ bàn phím n Pixel (n nhập từ bàn phím). Hiển thị thông tin các Pixel thuộc đường chéo chính và có màu xanh. 18
  19. BÀI 2: LỚP VÀ ĐỐI TƯỢNG Mã bài: MĐLVT 21.02 Giới thiệu Ngôn ngữ C++ được phát triển từ C lên, nó được bổ sung thêm tính hướng đối tượng. Các lớp (class) là tính năng trung tâm của C++ mà hỗ trợ lập trình hướng đối tượng và thường được gọi là các kiểu người dùng tự định nghĩa (user-defined). Một lớp được sử dụng để xác định form của một đối tượng và nó kết nối sự biểu diễn dữ liệu và các phương thức để thao tác các dữ liệu đó vào trong một package gọn gàng. Dữ liệu và hàm bên trong một lớp được gọi là các thành viên của lớp đó. Mục tiêu - Trình bày được các khái niệm Lớp, lớp đối tượng, thuộc tính, phương thức. - Trình bày được khái niệm về phạm vi thông tin trong lớp. - Trình bày được khái niệm và tác dục của hàm tạo, hàm hủy- Phân tích và xác định được các thành phần thuộc tính và phương thức của lớp. - Trình bày được cú pháp định nghĩa lớp, định nghĩa các thành phần của lớp với ngôn ngữ lập trình cụ thể. - Trình bày được cú pháp và xác định được nội dung hàm hủy, hàm tạo trong ngôn ngữ lập trình cụ thể. - Sử dụng được ngôn ngữ lập trình hướng đối tượng định nghĩa được lớp với các thành phần. - Phân tích và xác định được các lớp đối tượng trong bài toán thực tế. - Xây dựng được chương trình, sử dụng lớp đối tượng đã định nghĩa được. Nội dung 1. Định danh 1.1 Quy định với định danh Một khi phương thức được khai báo là trừu tượng thì khi một con trỏ gọi đến phương thức đó, chương trình sẽ thực hiện phương thức tương ứng với đối tượng mà con trỏ đang trỏ tới, thay vìthực hiện phương thức của lớp cùng kiểu với con trỏ. Đây được gọi là hiện tượng đa hình (tươngứng bội) trong C++. Chương trình 6.9 minh hoạ việc sử dụng phương thức trừu tượng: lớp Bus kế thừa từ lớp Car, hai lớp này cùng định nghĩa phương thức trừu tượng show(). 〈 Khi ta dùng một con trỏ có kiểu lớp Car trỏ vào địa chỉ của một đối tượng kiểu Car, nó sẽ gọi phương thức show() của lớpCar. 〈 Khi ta dùng cũng con trỏ đó, trỏ vào địa chỉ của một đối tượng kiểu Bus, nó sẽ gọi phương thức show() của lớpBus. Chương trình 6.9 hiển thị kết quả thông báo như sau: This is a Ford having a speed of 100km/h and its price is $3000 This is a bus of type Mercedes, on the line 27, having a speed of 150km/h and its price is $5000 Dòng thứ nhất là kết quả khi con trỏ ptrCar trỏ đến địa chỉ của đối tượng myCar, thuộc lớp Car nên sẽ gọi phương thức show() của lớp Car với các dữ liệu của đối tượng myCar: (100, Ford, 1463000). Dòng thứ hai tương ứng là kết quả khi con trỏ ptrCar trỏ đến địa chỉ của đối tượng myBus, thuộc lớp Bus nên sẽ gọi phương thức show() của lớp Bus, cùng với các tham số của đối tượng myBus: (150, Mercedes, 5000, 27). 19
  20. Lưu ý: Trong trường hợp ở lớp dẫn xuất không định nghĩa lại phương thức trừu tượng, thì chương trình sẽ gọi phương thức của lớp cơ sở, nhưng với dữ liệu của lớp dẫnxuất. Ví dụ, nếu trong chương trình 6.9, lớp Bus không định nghĩa chồng phương thức trừu tượng show() thì kết quả hiển thị sẽ là hai dòng thông báo giống nhau, chỉ khác nhau ở dữ liệu của hai đối tượng khác nhau: This is a Ford having a speed of 100km/h and its price is $3000 This is a Mercedes having a speed of 150km/h and its price is$5000 1.2.Quy ước với định danh Thông thường khi mới học lập trình c++ sẽ chỉ viết những chương trình đơn giản nên không quan tâm đến việc đặt tên trong c++. Nhưng sau này, khi làm những dự án lớn nếu không có cách đặt tên cụ thể thì sẽ rất khó hiểu cho cả mình với người khác. Nên trong bài này mình sẽ nói về một số quy ước đặt tên trong c++. Quy tắc chung 〈 Tên phải bắt đầu bằng chữ cái hoặc dấu gạch dưới _. Ví dụ: Laptrinh1, _Laptrinh 〈 Không được dùng những từ khóa như: const, char, int 〈 Tên không được có các toán tử. 〈 Hai biến trong cùng một hàm không được trùng tên. 〈 Tên biến không có dấu cách. Biến là một giá trị không thay đổi Các biến khai báo là const thì phải viết hoa toàn bộ tên biến hoặc đặt tên có chữ "k" đứng trước tên biến. Tên tệp. Tất cả các tên tệp phải là chữ thường và có thể bao gồm dấu gạch dưới ( _) hoặc dấu gạch ngang ( -). Tuân theo quy ước mà dự án của bạn sử dụng và đặt tên thật cụ thể. Ví dụ : 〈 my_useful_class.cc 〈 my-useful-class.cc Tên hàm Tên hàm trong c++ thường sẽ viết hoa chữ cái đầu của mỗi từ mới Class Tên class nên là một danh từ và sẽ viết hoa chữ cái đầu của tất cả các từ. Tên biến Tên biến trong c++ các bạn nên đặt là từ có ý ngh ĩa, ngắn gọn, dễ hi ểu có thể viêt thường, dung dấu gạch ngang "_" hoặc viết hoa khi có viết từ mới nhưng thông thường mình sẽ dùng dấu gạch ngang, miễn sao bạn tuân theo cách đặt tên chung mà mình đã 20
  21. nêu ở trên. 2. Các kiểu dữ liệu 2.1. Kiểu dữ liệu nguyên thủy Số nguyên, số thực, ký tự, boolean Kiểu dữ li ệu trong C++ xác định loại dữ li ệu mà một biến có thể l ưu trữ nh ư s ố nguyên, số thực, ký tự vv. Bạn có thể lưu thông tin của các kiểu dữ liệu (Data Type) đa dạng như Character, Wide Character, integer, floating-point, double floating point, Boolean, . Dựa trên kiểu dữ liệu của một biến, hệ thống sẽ cấp phát bộ nhớ và quyết định những gì có thể được lưu giữ trong bộ nhớ dành riêng đó.Tên tiếng Anh là Primitive Type, còn có thể gọi là kiểu dữ liệu gốc, kiểu dữ liệu cơ bản, hay kiểu dữ liệu có sẵn trong C++. Bên cạnh các kiểu dữ liệu gốc này, C++ cũng cung cấp các kiểu dữ liệu do người dùng tự định nghĩa (user-defined). Bảng dưới đây liệt kê danh sách 7 kiểu dữ liệu cơ bản trong C++: Kiểu dữ liệu Từ khóa Boolean bool Ký tự char Số nguyên int Số thực float Số thực dạng Double double Kiểu không có giá trị void Kiểu Wide character wchar_t Một số kiểu cơ bản có thể được sửa đổi bởi sử dụng một hoặc nhiều modifier sau: 〈 signed (kiểu có dấu) 〈 unsigned (kiểu không có dấu) 〈 short 〈 long Các loại dữ liệu nguyên thủy Các kiểu dữ liệu cơ bản dựa trên số nguyên và số thực. Ngôn ngữ C hỗ trợ cả signed và unsigned. Kích thước bộ nhớ của các loại dữ liệu cơ bản có thể thay đổi theo hệ điều hành 32 hoặc 64 bit. Hãy xem các kiểu dữ liệu cơ bản. Kích thước của nó được cho theo kiến trúc 32 bit. Bảng sau hiển thị kiểu biến, lượng bộ nhớ nó dùng để lưu giá trị trong bộ nhớ, và giá trị lớn nhất và nhỏ nhất có thể được lưu giữ với các kiểu biến đó: Kiểu Kích thước bộ nhớ Vùng giá trị 21
  22. char 1 byte -127 tới 127 hoặc 0 tới 255 unsigned char 1 byte 0 tới 255 signed char 1 byte -127 tới 127 int 4 byte -2147483648 tới 2147483647 unsigned int 4 byte 0 tới 4294967295 signed int 4 byte -2147483648 tới 2147483647 short int 2 byte -32768 tới 32767 unsigned short int Range 0 tới 65,535 signed short int Range -32768 tới 32767 long int 4 byte -2,147,483,647 tới 2,147,483,647 signed long int 4 byte Tương tự như long int unsigned long int 4 byte 0 tới 4,294,967,295 float 4 byte +/- 3.4e +/- 38 (~7 chữ số) double 8 byte +/- 1.7e +/- 308 (~15 chữ số) long double 8 byte +/- 1.7e +/- 308 (~15 chữ số) wchar_t 2 hoặc 4 byte 1 wide character Ví dụ sử dụng toán tử để lấy gia kích cỡ kiểu dữ liệu #include using namespace std; intmain() { cout << "Kich co cua char la: "<< sizeof(char) << endl; cout << "Kich co cua int la: "<< sizeof(int) << endl; cout << "Kich co cua short int la: "<< sizeof(shortint) << endl; cout << "Kich co cua long int la: "<< sizeof(longint) << endl; cout << "Kich co cua float la: "<< sizeof(float) << endl; cout << "Kich co cua double la: "<< sizeof(double) << endl; cout << "Kich co cua wchar_t la: "<< sizeof(wchar_t) << endl; return0; } Kết quả: Kich co cua char la: 1 Kich co cua int la: 4 Kich co cua short int la: 2 Kich co cua long int la: 4 22
  23. Kich co cua float la: 4 Kich co cua double la: 8 Kich co cua wchar_t la: 2 2.2.Giá trị hằng Hằng số trong C++ là một giá trị hoặc biến không thể thay đổi trong chương trình, ví dụ: 10, 20, 'a', 3.4, "lập trình c++", vv. Từ khóa const được sử dụng để định nghĩa hằng số trong lập trình C++. constfloatPI = 3.14; #include using namespace std; int main() { const float PI = 3.14; cout 2 usingnamespacestd; 3 4 /* 5 * Chương trình này chỉ ra diểm khác nhau giữa 6 * 2 kiểu số nguyên signed và unsigned. 7 */ 8 intmain() { 23
  24. 9 shortinti; // số nguyên signed short int 10 shortunsigned intj; // số nguyên unsigned short int 11 j = 32769; 12 i = j; 13 cout << i << " "<< j; 14 return0; 15 } Nó sẽ cho kết quả 1 -32767 32769 2.4.Khai báo và khởi tạo biến, hằng Cú pháp khai báo biến Cú pháp để khai báo một biến trong C: 1 type variable_list; Ví dụ về khai báo biến: 1 inta; 2 floatb; 3 charc; Ở đây, a, b, c là các biến và int, float, char là các kiểu dữ liệu. Chúng ta cũng có thể cung cấp giá trị trong khi khai báo các biến như được đưa ra dưới đây: 1 inta = 10, b = 20; // Khai báo 2 biến kiểu số nguyên 2 float= 20,8; 3 charc = 'A'; Quy tắc khai báo biến trong C 〈 Một biến có thể có các chữ cái, chữ số và dấu gạch dưới. 〈 Tên biến chỉ có thể bắt đầu bằng bảng chữ cái và dấu gạch dưới. Nó không thể bắt đầu bằng chữ số. 〈 Không có khoảng trắng trong tên biến. 〈 Tên biến không phải là bất kỳ từ hoặc từ khóa dành riêng như int, float, vv. Tên biến hợp lệ: inta; int_ab; inta30; Tên biến không hợp lệ: int2; inta b; intlong; 24
  25. 3. Toán tử 3.1.Toán tử số học Toán tử số học trong C++ Bảng dưới liệt kê các toán tử số học được hỗ trợ bởi ngôn ngữ C++: Giả sử biến A giữ giá trị 10, biến B giữ 20 thì: Toán Miêu tả Ví dụ tử + Cộng hai toán hạng A + B kết quả là 30 - Trừ toán hạng thứ hai từ toán hạng đầu A - B kết quả là -10 * Nhân hai toán hạng A * B kết quả là 200 / Phép chia B / A kết quả là 2 % Phép lấy số dư B % A kết quả là 0 ++ Toán tử tăng (++), tăng giá trị toán A++ kết quả là 11 hạng thêm một đơn vị Toán tử giảm ( ), giảm giá trị toán A kết quả là 9 hạng đi một đơn vị 3.2. Toán tử bit Toán tử so sánh bit trong C++ Toán tử so sánh bit làm việc trên đơn vị bit, tính toán biểu thức so sánh từng bit. Bảng dưới đây về &, |, và ^ như sau: p q p & q p | q p ^ q 0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 Giả sử nếu A = 60; và B = 13; thì bây giờ trong định dạng nhị phân chúng sẽ là như sau: A = 0011 1100 B = 0000 1101 A&B = 0000 1100 A|B = 0011 1101 25
  26. A^B = 0011 0001 ~A = 1100 0011 Các toán tử so sánh bit được hỗ trợ bởi ngôn ngữ C++ được liệt kê trong bảng dưới đây. Giá sử ta có biến A có giá tri 60 và biến B có giá trị 13, ta có: Ví dụ Toán Miêu tả Ví dụ tử & Toán tử AND (và) nhị phân sao chép một bit tới kết quả nếu nó (A & B) sẽ tồn tại trong cả hai toán hạng. cho kết quả là 12, tức là 0000 1100 | Toán tử OR (hoặc) nhị phân sao chép một bit tới kết quả nếu (A | B) sẽ cho nó tồn tại trong một hoặc hai toán hạng. kết quả là 61, tức là 0011 1101 ^ Toán tử XOR nhị phân sao chép bit mà nó chỉ tồn tại trong một (A ^ B) sẽ toán hạng mà không phải cả hai. cho kết quả là 49, tức là 0011 0001 ~ Toán tử đảo bit (đảo bit 1 thành bit 0 và ngược lại). (~A ) sẽ cho kết quả là -61, tức là 1100 0011. > Toán tử dịch phải. Giá trị toán hạng trái được dịch chuyển sang A >> 2 sẽ cho phải bởi số các bit được xác định bởi toán hạng bên phải. kết quả là 15, tức là 0000 1111 (dịch sang phải hai bit) 3.3.Toán tử quan hệ Toán tử quan hệ trong C++ Bảng dưới đây liệt kê các toán tử quan hệ được hỗ trợ bởi ngôn ngữ C++: Giả sử biến A giữ giá trị 10, biến B giữ 20 thì: 26
  27. Toán Miêu tả Ví dụ tử == Kiểm tra nếu 2 toán hạng bằng nhau hay không. Nếu (A == B) là không bằng thì điều kiện là true. đúng != Kiểm tra 2 toán hạng có giá trị khác nhau hay không. (A != B) là true Nếu không bằng thì điều kiện là true. > Kiểm tra nếu toán hạng bên trái có giá trị lớn hơn toán (A > B) là không hạng bên phải hay không. Nếu lớn hơn thì điều kiện là đúng true. = Kiểm tra nếu toán hạng bên trái có giá trị lớn hơn (A >= B) là không hoặc bằng giá trị của toán hạng bên phải hay không. đúng Nếu đúng là true. <= Kiểm tra nếu toán hạng bên trái có giá trị nhỏ hơn (A <= B) là true hoặc bằng toán hạng bên phải hay không. Nếu đúng là true. 3.4. Toán tử logic Toán tử logic trong C++ Bảng dưới đây chỉ rõ tất cả các toán tử logic được hỗ trợ bởi ngôn ngữ C. Giả sử biến A có giá trị 1 và biến B có giá trị 0: Ví dụ toán tử logic Toán Miêu tả Ví dụ tử && Được gọi là toán tử logic AND (và). Nếu cả hai toán tử đều (A && B) là có giá trị khác 0 thì điều kiện trở lên true. false. || Được gọi là toán tử logic OR (hoặc). Nếu một trong hai (A || B) là true. toán tử khác 0, thì điều kiện là true. ! Được gọi là toán tử NOT (phủ định). Sử dụng để đảo !(A && B) là ngược lại trạng thái logic của toán hạng đó. Nếu điều kiện true toán hạng là true thì phủ định nó sẽ là false. 3.5. Toán tử gán Toán tử gán trong C++ Dưới đây là những toán tử gán được hỗ trợ bởi ngôn ngữ C++: Ví dụ 27
  28. Toán Miêu tả Ví dụ tử = Toán tử gán đơn giản. Gán giá trị toán hạng bên C = A + B sẽ gán giá trị phải cho toán hạng trái. của A + B vào trong C += Thêm giá trị toán hạng phải tới toán hạng trái và C += A tương đương với gán giá trị đó cho toán hạng trái. C = C + A -= Trừ đi giá trị toán hạng phải từ toán hạng trái và C -= A tương đương với C gán giá trị này cho toán hạng trái. = C - A *= Nhân giá trị toán hạng phải với toán hạng trái và C *= A tương đương với gán giá trị này cho toán hạng trái. C = C * A /= Chia toán hạng trái cho toán hạng phải và gán giá C /= A tương đương với C trị này cho toán hạng trái. = C / A %= Lấy phần dư của phép chia toán hạng trái cho toán C %= A tương đương với hạng phải và gán cho toán hạng trái. C = C % A >= Dịch phải toán hạng trái sang số vị trí là giá trị toán C >>= 2 tương đương với hạng phải. C = C >> 2 &= Phép AND bit C &= 2 tương đương với C = C & 2 ^= Phép OR loại trừ bit C ^= 2 tương đương với C = C ^ 2 |= Phép OR bit. C |= 2 tương đương với C = C | 2 3.6.Toán tử một ngôi Dưới đây là một số toán tử hỗn hợp quan trọng được hỗ trợ bởi ngôn ngữ C++. Toán tử Miêu tả sizeof Toán tử sizeof trong C++ trả về kích cỡ của một biến. Ví dụ: sizeof(a), với a là integer, sẽ trả về 4 Điều kiện ? Toán tử điều kiện trong C++. Nếu Condition là true ? thì nó trả về giá X : Y trị X : nếu không thì trả về Y 28
  29. , Toán tử Comma trong C++ làm cho một dãy hoạt động được thực hiện. Giá trị của toàn biểu thức comma là giá trị của biểu thức cuối cùng trong danh sách được phân biệt bởi dấu phảy . (dot) và -> Toán tử thành viên trong C++ được sử dụng để tham chiếu các phần tử (arrow) đơn của các lớp, các cấu trúc, và union Cast Toán tử ép kiểu (Casting) trong C++ biến đổi một kiểu dữ liệu thành kiểu khác. Ví dụ: int(2.2000) sẽ trả về 2 & Toán tử con trỏ & trong C++ trả về địa chỉ của một biến. Ví du: &a; sẽ trả về địa chỉ thực sự của biến này * Toán tử con trỏ * trong C++ là trỏ tới một biến. Ví dụ: *var sẽ trỏ tới một biến var 4. Nhập và hiển thị dữ liệu lên màn hình 4.1 Hiển thị dữ liệu lên màn hình Sử dụng lệnh cout để xuất dữ liệu. Như bài viết trước mình đã nói, để có thể sử dụng được cout thì chúng ta cần khai báo thư viện iostream kèm theo câu lệnh “using namespace std“. Xét ví dụ nhé: Các bạn mở Dev C++ và viết lại code này giúp mình. #include usingnamespacestd; intmain() { cout > như sau: int variable; cin>> variable; Khi đó chương trình sẽ dừng lại và chờ đợi người sử dụng nhập dữ liệu vào từ bàn phím. Nếu cần nhập liên tục dữ liệu cho nhiều biến, có thể sử dụng toán tử >> liên tục trên cùng một hàm cin: cin>> variable_1 >> variable_2 >> >> variable_n; 29
  30. 5. Cấu trúc điều khiển 5.1. Lệnh if-else Một lệnh if có thể theo sau bởi một lệnh else (tùy ý: có hoặc không), mà có thể được thực hiện khi biểu thức logic có giá trị false. 5.2.Lệnh switch-case Cú pháp của cấu trúc rẽ nhánh switch case Muốn sử dụng cấu trúc switch case, sử dụng cú pháp sau: switch (expression) { case constant_1: { Statements; break; } case constant_2: { Statements; break; . . . case constant_n: { Statements; break; } default: { Statements; } 30
  31. } } Nguyên tắc hoạt động cấu trúc switch case Biểu thức nguyên trong switch được tính toán và kiểm tra lần lượt với giá trị của từng case. Đầu tiên, nó sẽ được so sánh với giá trị của case đầu tiên, nếu bằng nhau thì sẽ thực hiện các lệnh (statement) trong case này cho đến khi nó gặp được từ khoá break. Ngược lại, nếu như giá trị biểu thức nguyên không bằng giá trị case đầu tiên thì nó sẽ tiếp tục so sánh đến giá trị của case thứ hai và tiếp tục thực hiện như những bước trên. Giả sử, đến cuối cùng vẫn không tìm được giá trị bằng nó thì các khối lệnh trong default sẽ được thực hiện nếu như có tồn tại default. Khi cấu trúc switch case kết thúc, chương trình sẽ thực hiện tiếp những dòng lệnh sau cấu trúc switch case. Ta có sơ đồ hoạt động của cấu trúc switch case như sau: 31
  32. Sơ đồ cấu trúc switch case Một số lưu ý khi dùng cấu trúc rẽ nhánh switch case 〈 Các giá trị của mỗi case phải cùng kiểu dữ liệu với giá trị của biểu thức được so sánh. 〈 Số lượng các case là không giới hạn nhưng chỉ có thể có duy nhất 1 default. 〈 Giá trị của các case là 1 hằng số và các giá trị của các case phải khác nhau. 〈 Từ khóa break có thể sử dụng hoặc không. Nếu không được sử dụng thì chương trình sẽ không kết thúc cấu trúc switch case khi đã thực hiện hết khối lệnh của case đó. Thay vào đó, nó sẽ thực hiện tiếp các khối lệnh tiếp theo cho đến khi gặp từ khoá break hoặc dấu } cuối cùng của cấu 32
  33. trúc switch case. Vì vậy, các bạn có thể sử dụng 1 khối lệnh cho nhiều trường hợp khác nhau. 5.3. Vòng lặp while và do while Có một tình huống mà bạn cần phải thực hiện một đoạn code một vài lần. Nhìn chung, các câu lệnh được thực hiện một cách tuần tự. Câu lệnh đầu tiên của hàm được thực hiện trước, sau đó đến câu thứ 2 và tiếp tục. Ngôn ngữ lập trình cung cấp cho chúng ta nhiều cấu trúc điều khiển và cho phép bạn thực hiện những phần phức tạp. Vòng lặp cho phép thực hiện một lệnh và một nhóm lệnh nhiều lần , dưới đây là dạng tổng quát: Vòng lặp Miêu tả Vòng lặp while trong C++ Lặp lại một hoặc một nhóm các lệnh trong khi điều kiện đã cho là đúng. Nó kiểm tra điều kiện trước khi thực hiện thân vòng lặp. Vòng lặp do while trong Giống lệnh While, ngoại trừ ở điểm là nó kiểm tra điều C++ kiện ở cuối thân vòng lặp. Lồng vòng lặp trong C++ Bạn có thể sử dụng một hoặc nhiều vòng lặp trong các vòng lặp while, for hoặc do while khác. Các lệnh điều khiển vòng lặp trong C++ Các lệnh điều khiển vòng lặp thay đổi sự thực thi lệnh từ dãy thông thường của nó. Khi sự thực thi lệnh rời khỏi một phạm vi, tất cả các đối tượng tự động mà được tạo ra trong phạm vi đó bị hủy. 33
  34. C++ hỗ trợ các lệnh điều khiển vòng lặp sau đây.Click vào các đường link sau để biết thêm chi tiết. Lệnh điều khiển Miêu tả Lệnh break trong C++ Kết thúc vòng lặp hoặc lệnh switch và chuyển sang thực thi vòng lặp hoặc lệnh switch ngay sau nó. Lệnh continue trong C++ Khi gặp lệnh này thì chương trình sẽ bỏ qua các câu lệnh ở dưới nó (trong cùng một câu lệnh lặp) để thực hiện vòng lặp mới. Lệnh goto trong C++ Chuyển tới lệnh được gán. Mặc dù vậy, nó được khuyên rằng không nên sử dụng lệnh goto trong chương trình của bạn. 5.4.Vòng lặp for Vòng lặp for là một cấu trúc lặp được sử dụng nhiều nhất trong ngôn ngữ C++, nó hoàn toàn có thể thay thế cho vòng lặp while. Lập trình viên thường sử dụng vòng lặp for khi biết trước số lần lặp của vòng lặp. Cú pháp của vòng lặp for: for (init-statement; condition-expression; end-expression) { statements; } 5.5.Các lệnh làm thay đổi cấu trúc lập trình 5.6.Phạm vi biến Biến cục bộ trong C++ Các biến được khai báo bên trong một hàm hoặc khối là các biến cục bộ (local).Chúng chỉ có thể được sử dụng bởi các lệnh bên trong hàm hoặc khối code đó.Các biến cục bộ không được biết ở bên ngoài hàm đó (tức là chỉ được sử dụng bên trong hàm hoặc khối code đó). Dưới đây là ví dụ sử dụng các biến cục bộ: #include usingnamespace std; int main () { // phan khai bao bien cuc bo: int a, b; int c; // phan khoi tao bien a =10; b =20; 34
  35. c = a + b; cout usingnamespace std; 35
  36. #include using std::setw; int main () { int n[10];// n la mot mang gom 10 so nguyen // khoi tao gia tri cac phan tu cua mang n la 0 for(int i =0; i <10; i++) { n[ i ]= i +100;// thiet lap phan tu tai vi tri i la i + 100 } cout<<"Phan tu thu:"<< setw(13)<<"Gia tri la:"<< endl; // hien thi gia tri cua moi phan tu for(int j =0; j <10; j++) { cout<< setw(7)<< j << setw(13)<< n[ j ]<< endl; } return0; } 7.Lập trình với cấu trúc lặp và các thao tác với mảng trong Java 36
  37. Bài tập thực hành 1. Viết chương trình C++ giải phương trình bậc 2: ax2 + bx + c = 0. 2. Viết chương trình C++ tìm ước số chung lớn nhất (UCLN) và bội số chung nhỏ nhất (BCNN) của hai số a và b. 3. Viết chương trình C++ liệt kê tất cả các số nguyên tố nhỏ hơn n. 4. Viết chương trình C++ liệt kê n số nguyên tố đầu tiên. 5. Viết chương trình C++ liệt kê tất cả các số nguyên tố có 5 chữ số. 6. Viết chương trình C++ phân tích số nguyên n thành các thừa số nguyên tố. Ví dụ: 12 = 2 x 2 x 3. 7. Viết chương trình C++ tính tổng các chữ số của một số nguyên n. Ví dụ: 1234 = 1 + 2 + 3 + 4 = 10. 8. Viết chương trình C++ tìm các số thuận nghịch có 6 chữ số. Một số được gọi là số thuận nghịch nếu ta đọc từ trái sang phải hay từ phải sang trái số đó ta vẫn nhận được một số giống nhau. Ví dụ 123321 là một số thuận nghịch. 9. Nhập số tự nhiên n. Hãy liệt kê các số Fibonacci nhỏ hơn n là số nguyên tố. 10. Dãy số Fibonacci được định nghĩa như sau: F0 = 0, F1 = 1, F2 = 1, Fn = F(n-1) + F(n-2) với n >= 2. Ví dụ: 0, 1, 1, 2, 3, 5, 8, Hãy viết chương trình tìm số Fibonacci thứ n. 37
  38. BÀI 3: ĐÓNG GÓI VÀ XÂY DỰNG LỚP, TẠO VÀ SỬ DỤNG Mã bài: MĐLTV 21.03 Giới thiệu Data encapsulation là một kỹ thuật đóng gói dữ liệu, và các hàm mà sử dụng chúng và trừu tượng hóa dữ liệu là một kỹ thuật chỉ trưng bày tới các Interface và ẩn Implementation Detail (chi tiết trình triển khai) tới người sử dụng.C++ hỗ trợ các thuộc tính của đóng gói và ẩn dữ liệu thông qua việc tạo các kiểu tự định nghĩa (user- defined), gọi là classes. Chúng ta đã học rằng một lớp có thể chứa các thành viên private, protected và public. Theo mặc định, tất cả thành phần được định nghĩa trong một lớp là private Mục tiêu Hiểu và biết cách xây dựng lớp; tạo và sử dụng đối tượng thể hiện các kỹ thuật trừu tượng hóa dữ liệu; đóng gói và che giấu thông tin. Nội dung 1.Trừu tượng hóa dữ liệu 1.1.Trừu tượng hóa dữ liệu là gì? 1.2.Trừu tượng hóa dữ liệu là gì? Trừu tượng hóa dữ liệu (Data abstraction) liên quan tới việc chỉ cung cấp thông tin cần thiết tới bên ngoài và ẩn chi tiết cơ sở của chúng, ví dụ: để biểu diễn thông tin cần thiết trong chương trình mà không hiển thị chi tiết về chúng. Trừu tượng hóa dữ liệu (Data abstraction) là một kỹ thuật lập trình mà dựa trên sự phân biệt của Interface và Implementation (trình triển khai). Xem xét ví dụ về một chiếc TV, bạn có thể bật/tắt, thay đổi kênh, chỉnh âm lượng, và thêm các thiết bị ngoại vi như loa, VCR và DVD. Nhưng bạn không biết các chi tiết nội vi của nó, đó là, bạn không biết cách nó nhận tín hiệu qua không khí hoặc qua dây cáp, cách phiên dịch chúng và cuối cùng là hiển thị chúng trên màn hình. Vì thế, có thể nói rằng một chiếc TV phân biệt rõ ràng trình triển khai nội vi của nó với giao diện ngoại vi và bạn có thể thao tác với interface với các nút nguồn, điều khiển âm lượng mà không cần có bất kỳ hiểu biết về những gì diễn ra bên trong nó. Bây giờ, về mặt ngôn ngữ lập trình C++, thì các lớp C++ cung cấp Trừu tượng hóa dữ liệu (Data abstraction) ở mức thật tuyệt vời. Chúng cung cấp đủ các phương thức public tới bên ngoài để thao tác với tính năng của đối tượng và để thao tác dữ liệu đối tượng, ví dụ: trạng thái mà không cần thực sự biết về cách lớp đó đã được triển khai nội tại. Ví dụ, chương trình của bạn có thể tạo một lời gọi tới hàm sort() mà không cần biết về hàm đó thực sự sử dụng thuật toán gì để sắp xếp các giá trị đã cho. Thực ra, trình triển khai cơ sở (underlying implementation) của tính năng sắp xếp có thể thay đổi tùy vào thư viện, và miễn là Interface vẫn như cũ thì lời gọi hàm của bạn vẫn tiếp tục làm việc. Trong C++, chúng ta sử dụng các Lớp để định nghĩa kiểu dữ liệu trừu tượng (abstract data types (ADT)) của riêng chúng ta. Bạn có thể sử dụng đối tượng cout của lớp ostream cho luồng dữ liệu tới đầu ra chuẩn như sau: 1 #include 2 using namespace std; 38
  39. 3 int main( ) 4 { 5 cout usingnamespacestd; classStudent { public: intid; string name; }; intmain() { Student s1; // tao doi tuong Student s1.id = 10001; s1.name = "Vinh Tran"; cout << s1.id << endl; cout << s1.name << endl; return0; } Kết quả: 10001 Vinh Tran 39
  40. 2. Đóng gói và xây dựng lớp 2.1. Đóng gói là gì? 〈 Các lệnh (code) chương trình: Đây là phần chương trình mà thực hiện các hành động và cúng được gọi là các hàm. 〈 Dữ liệu chương trình: Dữ liệu là thông tin của chương trình mà tác động đến các hàm chương trình. Tính đóng gói (Encapsulation) là một khái niệm của lập trình hướng đối tượng mà ràng buộc dữ liệu và các hàm mà thao tác dữ liệu đó, và giữ chúng an toàn bởi ngăn cản sự gây trở ngại và sự lạm dụng từ bên ngoài. Tính đóng gói dẫn đến khái niệm OOP quan trọng là Data Hiding. Tính đóng gói - Data encapsulation là một kỹ thuật đóng gói dữ liệu, và các hàm mà sử dụng chúng và trừu tượng hóa dữ liệu là một kỹ thuật chỉ trưng bày tới các Interface và ẩn Implementation Detail (chi tiết trình triển khai) tới người sử dụng. C++ hỗ trợ các thuộc tính của đóng gói và ẩn dữ liệu thông qua việc tạo các kiểu tự định nghĩa (user-defined), gọi là classes. Chúng ta đã học rằng một lớp có thể chứa các thành viên private, protected và public. Theo mặc định, tất cả thành phần được định nghĩa trong một lớp là private. Ví dụ: ? 1 classBox 2 { 3 public: 4 doubletinhTheTich(void) 5 { 6 returnchieudai * chieurong * chieucao; 7 } 8 private: 9 doublechieudai; // Chieu dai cua mot box 10 doublechieurong; // Chieu rong cua mot box 11 doublechieucao; // Chieu cao cua mot box 12 }; Các biến chieudai, chieurong, và chieucao là private.Nghĩa là chúng chỉ có thể được truy cập bởi các thành viên khác của lớp Box, và không thể bởi bất kỳ phần khác trong chương trình của bạn.Đây là một cách thực hiện tính đóng gói trong C++. Để làm cho các phần của lớp là public (ví dụ: có thể truy cập tới các phần khác trong chương trình của bạn), bạn phải khai báo chúng sau từ khóa public. Tất cả biến và hàm được định nghĩa sau từ khóa public là có thể truy cập cho tất cả các hàm trong chương trình của bạn. 2.2. Xây dựng lớp Lớp (Class) là cách phân loại (classify) các đối tượng dựa trên đặc điểm chung của các đối tượng đó. • Lớp có thể coi là khuôn mẫu để tạo các đối tượng − Ví dụ: Người, Sinh Vật, Màu sắc • Lớp chính là kết quả của quá trình trừu tượng hóa dữ liệu − Lớp định nghĩa một kiểu dữ liệu mới, trừu tượng hóa một tập các đối tượng − Một đối tượng gọi là một thể hiện của lớp 40
  41. 2.3. Che giấu dữ liệu Đóng gói là một khái niệm trong lập trình hướng đối tượng, kết hợp giữa dữ liệu và các hàm thao tác dữ liệu với nhau, đồng thời đảm bảo sự an toàn và tránh khỏi sự can thiệp và sử dụng sai cách. Nó liên quan đến việc đóng gói các thành viên dữ liệu và các chức năng bên trong một lớp duy nhất.Đóng gói dữ liệu liên quan tới một khái niệm khác đó là che giấu dữ liệu. Nói chung, đóng gói là một quá trình gói các đoạn mã tương tự vào cùng một nơi. Tính năng đóng gói dữ liệu là một cơ chế đóng gói dữ liệu và các hàm sử dụng dữ liệu.Trừu tượng hóa dữ liệu là cơ chế chỉ để cho phép hiện ra các giao diện và ẩn dấu đi các chi tiết bên trong khỏi người dùng. C ++ hỗ trợ các thuộc tính đóng gói và che giấu dữ liệu thông qua việc tạo ra các kiểu dữ liệu do người dùng tự định nghĩa, được gọi là các lớp hay Class. Một lớp có thể chứa các thành viên trong phạm vi Private, Protected và Public. Theo mặc định, tất cả các thành viên sẽ được xác định trong phạm vi là Private. 2.4. Phương thức set/get 3. Tạo và sử dụng đối tượng 3.1. Khởi tạo dữ liệu Đây là cách khai báo các biến có cùng kiểu dữ liệu trên cùng một dòng đồng thời khởi tạo giá trị ban đầu cho mỗi biến. Khi khai báo nhiều biến trên cùng 1 dòng, mỗi biến được khai báo sẽ cách nhau bằng 1 dấu phẩy. Điều này hoàn toàn được cho phép trong C++. int number1 =4, number2 = 5; 3.2.Phương thức khởi tạo Hiện tại C++11 trở về sau hỗ trợ 3 loại constructor với mục đích sử dụng khác nhau nhằm tối ưu hóa cho từng trường hợp sử dụng cụ thể: 〈 Constructor: hàm tạo khởi tạo mới. 〈 Copy constructor: hàm tạo sao chép. 〈 Move constructor: hàm tạo dịch chuyển. Ứng với 3 tên gọi này là mục đích sử dụng của nó.Cả 3 phương thức đều tự động gọi khi đối tượng được tạo ra. 3.3.Khai báo và khởi tạo đối tượng Hàm khởi tạo (constructor) là một phương thức đặc biệt được gọi tự động tại thời điểm đối tượng được tạo.Mục đích của hàm khởi tạo là để khởi tạo các thành viên dữ liệu của đối tượng. Một hàm khởi tạo sẽ khác những hàm thông thường ở những điểm sau: 〈 Có tên trùng với tên lớp 〈 Không có kiểu dữ liệu trả về ( kể cả kiểu void) 〈 Tự động được gọi khi một đối tượng thuộc lớp được tạo ra 〈 Nếu chúng ta không khai báo một hàm khởi tạo, trình biên dịch C++ sẽ tự động tạo một hàm khởi tạo mặc định cho chúng ta (sẽ là hàm không có tham số nào và có phần thân trống). 3.4.Sử dụng đối tượng Xét ví dụ sau #include class Matrix4x4 41
  42. { private: double* data; public: Matrix4x4() { data = new double[4 * 4]; } Matrix4x4(const Matrix4x4& matrix) { data = new double[4 * 4]; memcpy(data, matrix.data, sizeof(double) * 4 * 4); } Matrix4x4(Matrix4x4&& matrix) { data = matrix.data; matrix.data = nullptr; } ~Matrix4x4() { if (data != nullptr) delete[] data; } Matrix4x4& operator=(const Matrix4x4& matrix) { memcpy(data, matrix.data, sizeof(double) * 4 * 4); return *this; } Copy constructor được sử dụng trong trường hợp tạo các giá trị mới nhưng cần sao chép ngay các dữ liệu của đối tượng có sẵn thay vì gọi constructor tốn kém hiệu năng và rồi gọi phương thức sao chép tốn kém thêm 1 lần hiệu năng nữa. 1 trường hợp điển hình sử dụng copy constructor thuận tiện là hoán đổi giá trị của 2 Matrix4x4 khi cần khai báo 1 Matrix4x4 temp. Matrix4x4 temp = m1; m1 = m2; m2 = temp; Dòng Matrix4x4 temp = m1 gọi copy constructor khi khởi tạo temp, trường hợp này dùng vậy rất thuật tiện và đỡ tốn hiệu năng. Matrix4x4(Matrix4x4 && matrix) Move constructor được gọi trong trường hợp khởi tạo đối tượng truyền vào 1 rvalue. Matrix4x4 m1, m2; 42
  43. Matrix4x4 m3(m1 + m2); Dòng Matrix4x4 m3(m1 + m2) trong đó m1 + m2 sẽ trả về 1 đối tượng tạm, sau dòng code này đối tượng đó sẽ hủy, trước C++11 chỉ có thể gọi copy constructor, m3 sẽ phải khởi khởi tạo vùng nhớ và sao chép dữ liệu từ đối tượng m1 + m2 dù biết rằng m1 + m2 sẽ không dùng nữa nhưng vẫn không thể "chiếm dụng" kết quả này, nhưng với C++11 thì khác, có thể tiến hành gọi move constructor vì biết m1 + m2 là rvalue, như phần hiện thực của move constructor có thể thấy dữ liệu tạm được "sang nhượng" cho m3. với chi phí thấp hơn copy constructor. Matrix4x4 operator+(const Matrix4x4& matrix) { Matrix4x4 result = *this; for (int i = 0; i 2 3 using namespace std; 4 5 class Employee { 6 public: 7 int id; //data member (bien instance) 8 string name; //data member(bien instance) 9 float salary; 10 Employee(int id, string name, float salary) { 11 this->id = id; 12 this->name = name; 13 this->salary = salary; 14 } 15 void display() { 16 cout << id << " " << name << " " << salary << endl; 17 } 43
  44. 18 }; int main(void) { Employee e1 = Employee(101, "Tran Thi Vinh", 500); // tao doi tuong Employee Employee e2 = Employee(102, "Dao Van Hoa", 1000); // tao doi tuong Employee e1.display(); e2.display(); return 0; } 101 Tran Thi Vinh 500 102 Dao Van Hoa 1000 5. Truyền tham số cho phương thức 5.1. Truyền tham số kiểu dữ liệu tham trị Ngôn ngữ lập trình C++ cho phép bạn truyền một con trỏ tới một hàm. Để truyền con trỏ tới hàm trong C++ bạn chỉ cần khai báo tham số hàm có kiểu con trỏ. Ví dụ sau chúng ta truyền một con trỏ unsigned long tới một hàm và thay đổi giá trị của nó bên trong hàm, truyền tham chiếu khi gọi hàm: #include #include usingnamespacestd; voidlaySoGiay(unsigned long*par); intmain() { unsigned longseconds; laySoGiay(&seconds) // in gia tri cout usingnamespacestd; // khai bao prototype ham: doublegiaTriTB(int*arr, intsize); intmain() { // khai bao mang so nguyen arr co 5 phan tu. intarr[5] = {10, 20, 100, 30, 60}; doubletrungbinh; // truyen con tro toi mang duoi dang mot tham so. 44
  45. trungbinh = giaTriTB(arr, 5); // hien thi ket qua cout usingnamespacestd; classinDuLieu { public: voidhamIn(inti) { cout << "In so nguyen: "<< i << endl; } voidhamIn(double f) { cout << "In so thuc: "<< f << endl; } voidhamIn(char* c) { cout << "In ky tu: "<< c << endl; } 45
  46. }; intmain(void) { inDuLieu idl; // Goi ham hamIn de in so nguyen idl.hamIn(12345); // Goi ham hamIn de in so thuc idl.hamIn(6677.02); // Goi ham hamIn de in ky tu idl.hamIn("Hoc C++ co ban va nang cao."); return0; } Biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau: 7. Xây dựng lớp đơn giản, tạo và sử dụng các đối tượng Để quản lý một hoặc nhiều đối tượng, trong lập trình hướng đối tượng người ta tạo ra một khung gọi là lớp.Trong lớp nó sẽ có các biến mà biến này ta gọi là các thuộc tính (properties), và lớp nó có thể chứa các hàm mà các hàm này chúng ta gọi nó là phương thức (method). Hình trên ta thấy có 1 class Car và 3 đối tượng Object1, Object1,Object3 Cú pháp khai báo lớp: class { private: public: 46
  47. protected: }; Trong đó: 〈 class : là từ khóa bắt buộc để định nghĩa một lớp đối tượng trong C++ 〈 Ten_lop : là do người dùng tự định nghĩa. Ten_lop có tính chất như định nghĩa kiểu dữ liệu để sử dụng sau này. Cách đặt tên lớp theo quy tắc đặt tên biến trong ngôn ngữ C++ Qui tắc khai báo lớp: Một lớp được định nghĩa bắt đầu với từ khóa class, theo sau là tên của 1 lớp, và cặp dấu ngoặc tròn bên trong chứa các thuộc tính (properties) và các phương thức (methods) thuộc về lớp. Tên lớp phải bắt đầu bằng 1 ký tự hoặc dấu gạch chân (_), theo sau là bất kỳ ký tự số, chữ cái hoa thường, hay dấu gạch chân và không trùng tên với các từ khóa của PHP. Tên lớp có thể diễn giải bằng biểu thức chính quy như sau: ^[a-zA-Z_\x7f-\xff][a-zA- Z0-9_\x7f-\xff]*$. Một lớp có thể chứa các hằng số, biến (hay gọi là thuộc tính) và các hàm (hay gọi là phương thức). Ví dụ: về 1 lớp cơ bản như sau: class Car{ }; Lưu ý: 〈 Từ khóa class là bắt buộc để định nghĩa một lớp đối tượng trong C++. Hơn nữa, C++ có phân biệt chữ hoa chữ thường trong khai báo cho nên chữ class phải được viết bằng chữ thường. Ví dụ: khai báo đúng class Car{ } Khai báo sai Class Car{// Lỗi từ khóa } 〈 Bắt buộc phải có dấu chấm phẩy “;” ở cuối định nghĩa lớp vì C++ coi định nghĩa một lớp như định nghĩa một kiểu dữ liệu, cho nên phải có dấu chấm phẩy cuối định nghĩa (tương tự định nghĩa kiểu dữ liệu kiểu cấu trúc). 〈 Để phân biệt với tên biến thông thường, ta nên (nhưng không bắt buộc) đặt tên lớp bắt đầu bằng một chữ in hoa và các tên biến bắt đầu bằng một chữ in thường. Sử dụng lớp đối tượng Lớp đối tượng được sử dụng khi ta khai báo các thể hiện của lớp đó.Một thể hiện của một lớp chính là một đối tượng cụ thể của lớp đó. Việc khai báo một thể hiện của một lớp được thực hiện như cú pháp khai báo một biến có kiểu lớp: ; Trong đó: 〈 Tên lớp: là tên lớp đối tượng đã được định nghĩa trước khi khai báo biến. 47
  48. 〈 Tên biến lớp: là tên đối tượng cụ thể. Tên biến lớp sẽ được sử dụng như các biến thông thường trong C++, ngoại trừ việc nó có kiểu lớp đối tượng. Ví dụ, muốn khai báo một thể hiện (biến) của lớp Car Car myCar; Sau đó, ta có thể sử dụng biến per trong chương trình như các biến thông thường: truyền tham số cho hàm, gán cho biến khác Lưu ý: • Khi khai báo biến lớp, ta không dùng lại từ khóa class nữa. Từ khóa class chỉ được sử dụng khi định nghĩa lớp mà không dùng khi khai báo biến lớp. Ví dụ, khai báo: Car myCar; // đúng là đúng, nhưng khai báo: class Car myCar; ; // Lỗi cú pháp là sai cú pháp. Các thành phần của lớp Việc khai báo các thành phần của lớp có dạng như sau: class { private: protected: public: }; Trong đó: 〈 private: là từ khóa chỉ tính chất của C++ để chỉ ra rằng các thành phần được khai báo trong phạm vi từ khóa này là riêng tư đối với lớp đối tượng. Các đối tượng của các lớp khác không truy nhập được các thành phần này. 〈 protected: các thành phần được khai báo trong phạm vi từ khóa này đều được bảo vệ. Qui định loại đối tượng nào được truy nhập đến các thành phần được bảo vệ 〈 public: các thành phần công cộng. Các đối tượng của các lớp khác đều có thể truy nhập đến các thành phần công cộng của một đối tượng bất kì. Các thành phần của lớp được chia làm hai loại: 1. Các thành phần chỉ dữ liệu của lớp, được gọi là thuộc tính của lớp 2. Các thành phần chỉ hành động của lớp, được gọi là phương thức của lớp. Thuộc tính của lớp Khai báo thuộc tính Thuộc tính của lớp là thành phần chứa dữ liệu, đặc trưng cho các tính chất của lớp. Thuộc tính của lớp được khai báo theo cú pháp sau: ; Trong đó: 〈 Kiểu dữ liệu: có thể là các kiểu dữ liệu cơ bản của C++, cũng có thể là các kiểu dữ liệu phức tạp do người dùng tự định nghĩa như struct, hoặc kiểu là một lớp đã được định nghĩa trước đó. 〈 Tên thuộc tính: là tên thuộc tính của lớp, có tính chất như một biến thông thường. Tên thuộc tính phải tuân theo quy tắc đặt tên biến của C++. Ví dụ, khai báo: class Car{ private: 48
  49. int speed; public: string mark; }; Khai báo một lớp xe ô tô (Car), có hai thuộc tính: thuộc tính tốc độ (speed) có tính chất private, thuộc tính nhãn hiệu xe (mark) có tính chất public. Lưu ý: 〈 Không được khởi tạo giá trị ban đầu cho các thuộc tính ngay trong lớp. Vì các thuộc tính chỉ có giá trị khi nó gắn với một đối tượng cụ thể, là một thể hiện (biến) của lớp. Ví dụ: class Car{ private: int speed; // đúng int weight = 500; // lỗi }; 〈 Khả năng truy nhập thuộc tính của lớp là phụ thuộc vào thuộc tính ấy được khai báo trong phạm vi của từ khóa nào: private, protected hay public. 〈 các hàm public truy nhập (get / set) đến thuộc tính đó. Thông thường, do yêu cầu đóng gói dữ liệu của hướng đối tượng, ta nên khai báo các thuộc tính có tính chất riêng tư (ptivate). Nếu muốn các đối tượng khác truy nhập được vào các thuộc tính này, ta xây dựng Sử dụng thuộc tính Thuộc tính có thể được sử dụng cho các chương trình nằm ngoài lớp thông qua tên biến lớp hoặc sử dụng ngay trong lớp bởi các phương thức của lớp. 〈 Nếu thuộc tính được dùng bên ngoài phạm vi lớp, cú pháp phải thông qua tên biến lớp (cách này chỉ sử dụng được với các biến có tính chất public): . ; 〈 Nếu thuộc tính được dùng bên trong lớp, cú pháp đơn giản hơn: ; Ví dụ, với định nghĩa lớp: class Car{ private: int speed; public: string mark; }; //ta khai báo một biến lớp: Car myCar; Thì có thể sử dụng thuộc tính nhãn hiệu xe khi in ra màn hình như sau: cout<< myCar.mark; Lưu ý: • Khi dùng thuộc tính bên trong các phương thức của lớp, mà tên thuộc tính lại bị trùng với tên biến toàn cục (tự do) của chương trình, ta phải chỉ rõ việc dùng tên thuộc 49
  50. tính của lớp (mà không phải tên biến toàn cục) bằng cách dùng chỉ thị phạm vi lớp “::” cú pháp: :: ; Phương thức của lớp Khai báo khuôn mẫu phương thức Một phương thức là một thao tác thực hiện một số hành động đặc trưng của lớp đối tượng. Phương thức được khai báo tương tự như các hàm trong C++: ([ ]); Trong đó: 〈 Kiểu trả về: là kiểu dữ liệu trả về của phương thức. Kiểu có thể là các kiểu dữ liệu cơ bản của C++, cũng có thể là kiểu do người dùng định nghĩa, hoặc kiểu lớp đã được định nghĩa. 〈 Tên phương thức: do người dùng tự đặt tên, tuân theo quy tắc đặt tên biến của C++. 〈 Các tham số: Các tham số đầu vào của phương thức, được biểu diễn bằng kiểu dữ liệu tương ứng. Các tham số được phân cách bởi dấu phẩy “,”. Các tham số là tùy chọn (Phần trong dấu ngoặc vuông “[]” là tùy chọn). Ví dụ, khai báo: class Car{ private: int speed; string mark; public: void show(); }; Định nghĩa một lớp Car có hai thuộc tính cục bộ là speed và mark, và khai báo một phương thức show() để mô tả đối tượng xe tương ứng. Show() là một phương thức không cần tham số và kiểu trả về là void. Lưu ý: Khả năng truy nhập phương thức từ bên ngoài là phụ thuộc vào phương thức được khai báo trong phạm vi của từ khóa nào: private, protected hay public. Định nghĩa phương thức Trong C++, việc cài đặt chi tiết nội dung của phương thức có thể tiến hành ngay trong phạm vi lớp hoặc bên ngoài phạm vi định nghĩa lớp. Cú pháp chỉ khác nhau ở dòng khai báo tên phương thức. Nếu cài đặt phương thức ngay trong phạm vi định nghĩa lớp, cú pháp là: ([ ]){ // Cài đặt chi tiết } Nếu cài đặt phương thức bên ngoài phạm vi định nghĩa lớp, ta phải dùng chỉ thị phạm vi “::” để chỉ ra rằng đấy là một phương thức của lớp mà không phải là một hàm tự do trong chương trình: :: ([ ]){ // Cài đặt chi tiết } 50
  51. Ví dụ, nếu cài đặt phương thức show() của lớp Car ngay trong phạm vi định nghĩa lớp, ta cài đặt như sau: class Car{ private: int speed; // Tốc độ string mark; // Nhãn hiệu public: void show(){ // Khai báo phương thức ngay trong lớp cout như khi cài đặt chi tiết một hàm tự do trong chương trình. 〈 Thông thường, chỉ các phương thức ngắn (trên một dòng) là nên cài đặt ngay trong lớp. Còn lại nên cài đặt các phương thức bên ngoài lớp để chương trình được sáng sủa, rõ ràng và dễ theo dõi. Sử dụng phương thức Cũng tương tự như các thuộc tính của lớp, các phương thức cũng có thể được sử dụng bên ngoài lớp thông qua tên biến lớp, hoặc có thể được dùng ngay trong lớp bởi các phương thức khác của lớp định nghĩa nó. Nếu phương thức được dùng bên ngoài phạm vi lớp, cú pháp phải thông qua tên biến lớp (cách này chỉ sử dụng được với các phương thức có tính chất public): . ([ ]); Nếu thuộc tính được dùng bên trong lớp, cú pháp đơn giản hơn: ([ ]); Ví dụ, với định nghĩa lớp: class Car{ private: int speed; // Tốc độ string mark; // Nhãn hiệu public: 51
  52. void show(); // Giới thiệu xe }; /* Khai báo phương thức bên ngoài lớp */ void Car::show(){ cout :: ([ ]); Chương trình cài đặt đầy đủ một lớp xe ô tô (Car) với các thuộc tính có tính chất cục bộ: 〈 Tốc độ xe (speed) 〈 Nhãn hiệu xe (mark) 〈 Giá xe (price) Và các phương thức có tính chất public: 〈 Khởi tạo các tham số (init) 〈 Giới thiệu xe (show) 〈 Các phương thức truy nhập (get/set) các thuộc tính Sau đó, chương trình main sẽ sử dụng lớp Car này để định nghĩa các đối tượng cụ thể và sử dụng các phương thức của lớp này. #include #include using namespace std; /* Định nghĩa lớp */ class Car { private: int speed; // Tốc độ string mark; // Nhãn hiệu float price; // Giá xe public: void setSpeed(int); // Gán tốc độ cho xe int getSpeed(); // Lấy tốc độ xe void setMark(string); // Gán nhãn cho xe string getMark(); // Lấy nhãn xe void setPrice(float); // Gán giá cho xe float getPrice(); // Lấy giá xe void init(int, string, float);// Khởi tạo thông tin về xe 52
  53. void show(); // Hiển thị thông tin về xe }; /* Khai báo phương thức bên ngoài lớp */ void Car::setSpeed(int speedIn) { // Gán tốc độ cho xe speed = speedIn; } int Car::getSpeed() { // Lấy tốc độ xe return speed; } void Car::setMark(string markIn) { // Gán nhãn cho xe mark = markIn; } string Car::getMark() { // Lấy nhãn xe return mark; } void Car::setPrice(float priceIn) { // Gán giá cho xe price = priceIn; } float Car::getPrice() { // Lấy giá xe return price; } void Car::init(int speedIn, string markIn, float priceIn) { speed = speedIn; mark = markIn; price = priceIn; return; } void Car::show() { // Phương thức hiển thị xe cout<< "This is a" << mark << "having a speed of " << speed << "km/h and its price is $" << price << endl; return; } // Hàm main, chuong trình chính int main() { Car myCar; // Khai báo bie // Kh?i t?o l?n th? nh?t cout<< "Xe thu nhat: " << endl; myCar.init(100, "Ford", 3000); cout<< "Toc do (km/h): " << myCar.getSpeed() << endl; 53
  54. cout<< "Nhan hieu :" << myCar.getMark() << endl; cout<< "Gia ($):" << myCar.getPrice() << endl; // Thay d?i thu?c tính xe cout<< "Xe thu hai:" << endl; myCar.setSpeed(150); myCar.setMark("Mercedes"); myCar.setPrice(5000); myCar.show(); system("pause"); return 0; } Kết quả: Xe thu nhat: Toc do (km/h): 100 Nhan hieu: Ford Gia ($): 3000 Xe thu hai: This is a Mercedes having a speed of 150km/h and its price is $5000 Phạm vi truy nhập lớp Trong C++, có một số khái niệm về phạm vi, xếp từ bé đến lớn như sau: 〈 Phạm vi khối lệnh: Trong phạm vi giữa hai dấu giới hạn “{}” của một khối lệnh. Ví dụ các lệnh trong khối lệnh lặp while(){} sẽ có cùng phạm vi khối lệnh. 〈 Phạm vi hàm: Các lệnh trong cùng một hàm có cùng mức phạm vi hàm. 〈 Phạm vi lớp: Các thành phần của cùng một lớp có cùng phạm vi lớp với nhau: các thuộc tính và các phương thức của cùng một lớp. 〈 Phạm vi chương trình (còn gọi là phạm vi tệp): Các lớp, các hàm, các biến được khai báo và định nghĩa trong cùng một tệp chương trình thì có cùng phạm vi chương trình. 〈 Trong phạm vi truy nhập lớp, ta chỉ quan tâm đến hai phạm vi lớn nhất, đó là phạm vi lớp và phạm vi chương trình. Trong C++, phạm vi truy nhập lớp được quy định bởi các từ khóa về thuộc tính truy nhập: 〈 private: Các thành phần của lớp có thuộc tính private thì chỉ có thể được truy nhập trong phạm vi lớp. 〈 protected: Trong cùng một lớp, thuộc tính protected cũng có ảnh hưởng tương tự như thuộc tính private: các thành phần lớp có thuộc tính protected chỉ có thể được truy nhập trong phạm vi lớp. Ngoài ra nó còn có thể được truy nhập trong các lớp con khi có kế thừa 〈 public: các thành phần lớp có thuộc tính public thì có thể được truy nhập trong phạm vi chương trình, có nghĩa là nó có thể được truy nhập trong các hàm tự do, các phương thức bên trong các lớp khác Ví dụ, thuộc tính price của lớp Car có tính chất private nên chỉ có thể truy nhập bởi các phương thức của lớp Car. Không thể truy nhập từ bên ngoài lớp (phạm vi chương trình), chẳng hạn trong một hàm tự do ngoài lớp Car. void Car::setPrice(float priceIn){ price = priceIn; // Đúng, vì setPrice là một phương thức của lớp Car 54
  55. } nhưng: void freeFunction(Car myCar){ myCar.price = 3000;// Lỗi, vì freeFunction là một hàm tự do // nằm ngoài phạm vi lớp Car } Khi đó, hàm freeFunction phải truy nhập gián tiếp đến thuộc tính price thông qua phương thức truy nhập có tính chất public như sau: void freeFunction(Car myCar){ myCar.setPrice(3000);// Đúng, vì setPrice là một phương thức của // lớp Car có thuộc tính public } Tuy nhiên, C++ cho phép một cách đặc biệt để truy nhập đến các thành phần private và protected của một lớp bằng khái niệm hàm bạn và lớp bạn của một lớp: trong các hàm bạn và lớp bạn của một lớp, có thể truy nhập đến các thành phần private và protected như bên trong phạm vi lớp đó. Sự khác nhau giữa lớp và đối tượng trong C++ Sự khác nhau giữa lớp và đối tượng trong C++ được thống kê trong bảng sau: STT Đối tượng Lớp Đối tượng là thể hiện của Lớp là một khuân mẫu hay thiết kế để tạo ra các đối 1. 1 lớp. tượng. Đối tượng là 1 thực thể 2. trong thế giới thực như Lớp là một nhóm các đối tượng tương tự nhau. Bút chì, Xe đạp, Đối tượng là 1 thực thể vật 3. Lớp là 1 thực thể logic lý Đối tượng được tạo ra chủ yếu từ từ khóa new. Lớp được khai báo bằng việc sử dụng từ khóa class. 4. Ví dụ: Student s1=new Ví dụ: class Student{} Student(); Đối tượng có thể được tạo 5. Lớp được khai báo 1 lần duy nhất. nhiều lần. Đối tượng được cấp bộ 6. Lớp không được cấp bộ nhớ khi nó được tạo ra. nhớ khi nó được tạo ra. Chỉ có một cách để tạo ra Chỉ có một cách để định nghĩa lớp trong C++ sử dụng 7. đối tượng trong C++ như từ khoá class. từ khóa new 8. Lớp String, StringBuilder, StringBuffer. Sự khác nhau giữa StringBuffer và StringBuilder trong java Sự khác nhau giữa StringBuffer và StringBuilder trong java được thể hiện trong bảng sau: No. StringBuffer StringBuilder 1) StringBuffer là đồng bộ StringBuilder là không đồng bộ (non- (synchronized) tức là luồng an synchronized) tức là luồng không an toàn. Điều này 55
  56. toàn. Điều này có nghĩa là không có nghĩa là có 2 luồng cùng truy cập phương thức thể có 2 luồng cùng truy cập của lớp StringBuilder đồng thời. phương thức của lớp StringBuffer đồng thời. 2) StringBuffer không hiệu quả bằng StringBuilder hiệu quả hơn StringBuffer. StringBuilder. Ví dụ về StringBuffer trong java ? 1 publicclassBufferTest { 2 publicstaticvoidmain(String[] args) { 3 StringBuffer buffer = newStringBuffer("hello"); 4 buffer.append("java"); 5 System.out.println(buffer); 6 } 7 } Output: hellojava Ví dụ về StringBuilder trong java ? 1 publicclassBuilderTest { 2 publicstaticvoidmain(String[] args) { 3 StringBuilder builder = newStringBuilder("hello"); 4 builder.append("java"); 5 System.out.println(builder); 6 } 7 } Output: hellojava Test hiệu suất của StringBuffer và StringBuilder trong java trong java ? 1 publicclassConcatTest { 2 publicstaticvoidmain(String[] args) { 3 longstartTime = System.currentTimeMillis(); 4 StringBuffer sb = newStringBuffer("Java"); 5 for(inti = 0; i < 100000; i++) { 6 sb.append("Hello"); 7 } 8 System.out.println("Thời gian nối chuỗi của StringBuffer: " 9 + (System.currentTimeMillis() - startTime) + "ms"); 10 startTime = System.currentTimeMillis(); 11 StringBuilder sb2 = newStringBuilder("Java"); 12 for(inti = 0; i < 100000; i++) { 13 sb2.append("Hello"); 14 } 15 System.out.println("Thời gian nối chuỗi của StringBuilder: " 56
  57. 16 + (System.currentTimeMillis() - startTime) + "ms"); 17 } Output: Thời gian nối chuỗi của StringBuffer: 11ms Thời gian nối chuỗi của StringBuilder: 5ms 57
  58. Bài tập thực hành Hãy viết chương trình thực hiện các yêu cầu sau: Xây dựng lớp Color gồm: Thuộc tính: TenMau, MaMau Phương thức: 〈 Cấu tử không tham số 〈 Cấu tử có tham số 〈 Hủy 〈 Nạp chồng toán tử nhập 〈 Nạp chồng toán tử xuất 〈 getTenMau() : hàm trả về TenMau Xây dựng lớp Point gồm: Thuộc tính: int x, y Phương thức: 〈 Cấu tử không tham số 〈 Cấu tử có tham số 〈 Hủy 〈 Nạp chồng toán tử nhập 〈 Nạp chồng toán tử xuất 〈 CheoChinh : hàm kiểm tra Point có thuộc đường chéo chính hay không (1 điểm thuộc đường chéo chính khi và chỉ khi tung độ bằng hoành độ). Xây dựng lớp Pixel kế thừa từ lớp Color và Point bao gồm thêm: Phương thức: 〈 Cấu tử không tham số 〈 Cấu tử có tham số 〈 Nạp chồng toán tử nhập 〈 Nạp chồng toán tử xuất 〈 KiemTra: hàm kiểm tra Pixel thuộc đường chéo chính và có màu “Xanh” hay không? Chương trình chính: Nhập vào từ bàn phím n Pixel (n nhập từ bàn phím). Hiển thị thông tin các Pixel thuộc đường chéo chính và có màu xanh. 58
  59. BÀI 4: TỔNG QUAN VỀ JDBC Mã bài: MĐLTV 21.04 Giới thiệu JDBC viết tắt của Java Database Connectivity, cho phép các ứng dụng Java kết nối với nhiều cơ sở dữ liệu được cài đặt trên các hệ quản trị cơ sở dữ liệu như MySQL, SQL Server, Oracle, PostgreSQL, Trước khi có JDBC, ODBC API được sử dụng là API để kết nối và thực thi truy vấn với cơ sở dữ liệu. Nhưng API này có một hạn chế rõ ràng là nó sử dụng ODBC driver được viết bằng ngôn ngữ C (là phụ thuộc nền tảng và không an toàn). Do đó, Java đã định nghĩa riêng API (là JDBC API) để thực hiện các thao tác khi làm việc với cơ sở dữ liệu, và tất nhiên các JDBC driver này được viết bằng ngôn ngữ Java để cung cấp các lợi thế rõ rệt của ngôn ngữ này. Mục tiêu Hiểu và biết cách xây dựng ứng dụng JDBC cơ bản; thực hiện kết nối với cơ sở dữ liệu Cài đặt dược IDBC Kết nối được cơ sở dữ liệu theo yêu cầu Nội dung 1. Tổng quan về JDBC JDBC API cung cấp các Class và Interface sau: DriverManager: Lớp này quản lý các Database Driver. Ánh xạ các yêu cầu kết nối từ ứng dụng Java với Data driver thích hợp bởi sử dụng giao thức kết nối phụ. Driver: Interface này xử lý các kết nối với Database Server. Hiếm khi, bạn tương tác trực tiếp với các đối tượng Driver này.Thay vào đó, bạn sử dụng các đối tượng DriverManager để quản lý các đối tượng kiểu này. Connection: Đối tượng Connection biểu diễn ngữ cảnh giao tiếp. Interface này chứa nhiều phương thức đa dạng để tạo kết nối với một Database. Statement: Bạn sử dụng các đối tượng được tạo từ Interface này để đệ trình các lệnh SQL tới Database. Ngoài ra, một số Interface kết thừa từ nó cung chấp nhận thêm các tham số để thực thi các thủ tục đã được lưu trữ. ResultSet: Các đối tượng này giữ dữ liệu được thu nhận từ một Database sau khi bạn thực thi một truy vấn SQL. Nó nóng vai trò như một Iterator để cho phép bạn vọc qua dữ liệu của nó. SQLException: Lớp này xử lý bất cứ lỗi nào xuất hiện trong khi làm việc với Database. 2. Cài đặt JDBC Để làm việc với JDBC, bạn cần cài đặt Java và một cơ sở dữ liệu, chẳng hạn MySQL. Để cài đặt Java, bạn theo hướng dẫn chi tiết trong chương Cài đặt Java. Khi bạn đã cài đặt xong J2SE Development Kit 5.0 (JDK 5.0), thì bạn sẽ có các JDBC package là java.sql and javax.sql trong đó. Để cài đặt MySQL, bạn theo hướng dẫn chi tiết trong chương Cài đặt MySQL. Khi làm việc với JDBC, bạn cần đảm bảo là MySQL server của bạn đã được bật. Đã có app VietJack trên điện thoại, giải bài tập SGK, SBT Soạn văn, Văn mẫu, Thi online, Bài giảng miễn phí.Tải ngay ứng dụng trên Android và iOS. 59
  60. Các bạn có thể mua thêm khóa học JAVA CORE ONLINE VÀ ỨNG DỤNG cực hay, giúp các bạn vượt qua các dự án trên trường và đi thực tập Java. Khóa học có giá chỉ 300K, nhằm ưu đãi, tạo điều kiện cho sinh viên cho thể mua khóa học. Nội dung khóa học gồm 16 chuơng và 100 video cực hay, học trực tiếp tại tap/ Bạn nào có nhu cầu mua, inbox trực tiếp a Tuyền, cựu sinh viên Bách Khoa K53, fb: Follow facebook cá nhân Nguyễn Thanh Tuyền để tiếp tục theo dõi các loạt bài mới nhất về Java,C,C++,Javascript,HTML,Python,Database,Mobile mới nhất của chúng tôi. 3. Kết nối cơ sở dữ liệu Bước 1: Import các package Bạn thêm lệnh import trong chương trình Java để bao các lớp cần thiết. Bước 2: Đăng ký JDBC driver. Bạn có thể tìm hiểu cách import lib trong Java bởi link sau vietjack.com/java_jdbc/cach_them_file_jar_lib_trong_java.jsp Bước này làm JVM tải trình triển khai driver cụ thể vào trong bộ nhớ để nó có thể thực hiện các yêu cầu JDBC của bạn. Bước 3: Tạo địa chỉ Database URL chính xác Bước này rất quan trọng và thường xuất hiện khá nhiều lỗi trong khi bạn tạo một địa chỉ thích hợp để trỏ tới Database mà bạn muốn kết nối. Bước 4: Tạo đối tượng Connection Bạn gọi phương thức getConnection() của đối tượng DriverManager để thành lập kết nối tới cơ sở dữ liệu thực sự. Phần dưới đây trình bày chi tiết về các bước trên. Bước 1: Import các JDBC package Lệnh import nói cho Java Compiler nơi để tìm các lớp mà bạn muốn tham chiếu trong code và lệnh này được đặt ở phần đầu tiên của code. Để sử dụng JDBC package chuẩn để cho phép bạn chọn, cập nhật và xóa dữ liệu trong các bảng SQL, bạn thêm các dòng sau: import java.sql.*;// cho cac chuong trinh JDBC chuan import java.math.*;// de ho tro BigDecimal va BigInteger Bước 2: Đăng ký JDBC driver Trước khi sử dụng bất kỳ driver nào, bạn cần đăng ký nó. Trong chương trình, bạn chỉ cần thực hiện một lần tiến trình đăng ký này, theo một trong hai cách sau: Sử dụng phương thức Class.forName() Sử dụng phương thức Class.forName() là hướng tiếp cận chung và phổ biến để đăng ký một driver. Dưới đây là cú pháp: publicstaticvoidClass.forName(String ten_lop)throwsClassNotFoundException Ví dụ, để đăng ký Oracle driver, bạn sử dụng mẫu sau: try{ Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); } catch(ClassNotFoundException ex){ System.out.println("Error: khong the tai lop Driver!"); System.exit(1); 60
  61. catch(IllegalAccessException ex){ System.out.println("Error: xuat hien van de truy cap trong khi tai!"); System.exit(2); catch(InstantiationException ex){ System.out.println("Error: khong the khoi tao Driver!"); System.exit(3); } Sử dụng DriverManager.registerDriver() Nếu bạn đang sử dụng một JDK không tuân theo JVM (được cung cấp bởi Microsoft chẳng hạn), thì bạn nên sử dụng phương thức DriverManager.registerDriver() này. Ví dụ: try{ Driver myDriver =neworacle.jdbc.driver.OracleDriver(); DriverManager.registerDriver( myDriver ); } catch(ClassNotFoundException ex){ System.out.println("Error: khong the tai lop Driver!"); System.exit(1); 4. Tạo ứng dụng JDBC Bước 1: Import các package Trong bước này, chúng ta cần import các package chứa các lớp JDBC cần thiết cho lập trình Database. Thông thường chỉ cần sử dụng import java.sql.*. Bước 2: Đăng ký JDBC driver Trong bước này, cần khởi tạo một driver để có thể mở một kênh giao tiếp với cơ sở dữ liệu. Bước 3: Mở một kết nối Sử dụng phương thức DriverManager.getConnection() để tạo một đối tượng Connection biểu diễn một kết nối vật lý với cơ sở dữ liệu. Bước 4: Thực thi một truy vấn Cần sử dụng một đối tượng của kiểu Statement để xây dựng và đệ trình một lệnh SQL tới cơ sở dữ liệu. Bước 5: Lấy dữ liệu từ ResultSet Sử dụng phương thức ResultSet.getXXX() để thu nhận dữ liệu từ Result Set. Bước 6: Dọn sạch môi trường và giải phóng resource Sau khi đã làm việc xong, cần đóng tất cả các Database Resource Ví dụ về tạo ứng dụng JDBC đơn giản Dưới đây là code ví dụ để tạo một ứng dụng JDB package com.hoclaptrinh.jdbc; //Buoc 1: Ban can inport cac package can thiet import java.sql.*; public class ViDuJDBC { // Ten cua driver va dia chi URL cua co so du lieu static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/sinhvien"; 61
  62. // Ten nguoi dung va mat khau cua co so du lieu static final String USER = "root"; static final String PASS = "123456"; public static void main(String[] args) { Connection conn = null; Statement stmt = null; try{ // Buoc 2: Dang ky Driver Class.forName("com.mysql.jdbc.Driver"); // Buoc 3: Mo mot ket noi System.out.println("Dang ket noi toi co so du lieu "); conn = DriverManager.getConnection(DB_URL,USER,PASS); // Buoc 4: Thuc thi truy van System.out.println("Tao cac lenh truy van SQL "); stmt = conn.createStatement(); String sql; sql = "SELECT mssv, ho, ten, diemthi FROM sinhvienk60"; ResultSet rs = stmt.executeQuery(sql); // Buoc 5: Lay du lieu tu Result Set while(rs.next()){ // Lay du lieu boi su dung ten cot int mssv = rs.getInt("mssv"); int diemthi = rs.getInt("diemthi"); String ho = rs.getString("ho"); String ten = rs.getString("ten"); // Hien thi cac gia tri System.out.print("\nMSSV: " + mssv); System.out.print("\nHo: " + ho); System.out.println("\nTen: " + ten); System.out.print("\nDiem Thi: " + diemthi); System.out.print("\n===");} // Buoc 6: Don sach moi truong va giai phong resource rs.close(); stmt.close(); conn.close(); }catch(SQLException se){ // Xu ly cac loi cho JDBC se.printStackTrace(); }catch(Exception e){ // Xu ly cac loi cho Class.forName e.printStackTrace(); }finally{ 62
  63. // Khoi finally duoc su dung de dong cac resource try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ } try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }// Ket thuc khoi finally }// Ket thuc khoi try }// Ket thuc main }// Ket thuc ViDuJDBC 63
  64. BÀI 5: KẾ THỪA Mã bài: MĐLTV 21.05 Giới thiệu Kế thừa là một trong những tính năng chính của lập trình hướng đối tượng trong C++.Nó cho phép người dùng tạo một lớp (lớp kế thừa) từ một lớp có sẵn (lớp chính). Lớp kế thừa sẽ kế thừa toàn bộ tính năng của lớp chính và có thể có các tính năng bổ sung của riêng nó. Kế thừa là một trong những tính năng chính của lập trình hướng đối tượng trong C++.Nó cho phép người dùng tạo một lớp (lớp kế thừa) từ một lớp có sẵn (lớp chính). Lớp kế thừa sẽ kế thừa toàn bộ tính năng của lớp chính và có thể có các tính năng bổ sung của riêng nó. Mục tiêu - Trình bày được lớp cơ sở, lớp dẫn xuất - Trình bày được đơn kế thừa, đa kế thừa - Sử dụng được kế thừa vào trong bài tập Nội dung 1. Một số khái niệm cơ bản 1.1 Tổng quát hóa và đặc biệt hóa 1.2. Tính kế thừa Một trong những khái niệm quan trọng nhất trong lập trình hướng đối tượng là Tính kế thừa (Inheritance).Tính kế thừa cho phép chúng ta định nghĩa một lớp trong điều kiện một lớp khác, mà làm cho nó dễ dàng hơn để tạo và duy trì một ứng dụng.Điều này cũng cung cấp một cơ hội để tái sử dụng tính năng code và thời gian thực thi nhanh hơn. Khi tạo một lớp, thay vì viết toàn bộ các thành viên dữ liệu và các hàm thành viên mới, lập trình viên có thể nên kế thừa các thành viên của một lớp đang tồn tại.Lớp đang tồn tại này được gọi là Base Class - lớp cơ sở, và lớp mới được xem như là Derived Class – lớp thừa kế. 1.3. Lớp cơ sở, lớp dẫn xuất Lớp cơ sở (Base Class) và Lớp thừa kế (Derived Class) trong C++ Một lớp có thể được kế thừa từ hơn một lớp khác, nghĩa là, nó có thể kế thừa dữ liệu và hàm từ nhiều lớp cơ sở.Để định nghĩa một lớp kế thừa (Derived Class), chúng ta sử dụng một danh sách để xác định các lớp cơ sở. Danh sách này liệt kê một hoặc nhiều lớp cơ sở và có form sau: class lop_ke_thua: access_modifier lop_co_so Ở đây, access_modifier là public, protected hoặc private, và lop_co_so là tên của lớp đã được định nghĩa trước đó. Nếu access_modifier không được sử dụng, thì mặc định là private. 64
  65. Bạn xem xét ví dụ sau với Hinh là lớp cơ sở và HinhChuNhat là lớp kế thừa: #include using namespace std; // lop co so: Hinh class Hinh { public: void setChieuRong(int rong) { chieurong = rong; } void setChieuCao(int cao) { chieucao = cao; } protected: int chieurong; int chieucao; }; // day la lop ke thua: HinhChuNhat class HinhChuNhat: public Hinh { public: int tinhDienTich() { return chieurong * chieucao; } }; int main(void) { HinhChuNhat Hcn; Hcn.setChieuRong(14); Hcn.setChieuCao(30); // in dien tich cua doi tuong. cout<< "Tong dien tich la: " << Hcn.tinhDienTich() << endl; return 0; } 65
  66. 1.4. Các dạng kế thừa 1.4.1. Đơn kế thừa Thừa kế (Inheritance) là một trong 4 tính chất quan trọng của OOP, là thao tác cho phép một class Con có được các thuộc tính và thao tác của class Cha, như thể các thuộc tính và thao tác đó đã được định nghĩa tại class Con. Ví dụ: class Con có thể sử dụng hàm PrintAge() của class Cha, nên kết quả console là 18. 1.4.2. Đa kế thừa Đa kế thừa trong C++ Một lớp trong C++ có thể kế thừa các thành viên từ nhiều lớp, và đây là cú pháp: class lop_ke_thua: access_modifier lop_co_so_1, access_modifier lop_co_so_2 Tại đây, access_modifier là public, protected hoặc private và sẽ được cung cấp cho mỗi lớp cơ sở, và chúng sẽ được phân biệt với nhau bởi dấu phảy như trên. Bạn thử ví dụ sau: #include 66
  67. using namespace std; // lop co so: Hinh class Hinh { public: void setChieuRong(int rong) { chieurong = rong; } void setChieuCao(int cao) { chieucao = cao; } protected: int chieurong; int chieucao; }; // lop co so: ChiPhiSonMau class ChiPhiSonMau { public: int tinhChiPhi(int dientich) { return dientich * 300000; } }; // day la lop ke thua: HinhChuNhat class HinhChuNhat: public Hinh, public ChiPhiSonMau { public: int tinhDienTich() { return chieurong * chieucao; } }; int main(void) { HinhChuNhat Hcn; int dientich; Hcn.setChieuRong(14); 67
  68. Hcn.setChieuCao(30); dientich = Hcn.tinhDienTich(); // in dien tich cua doi tuong. cout<< "Tong dien tich la: " << Hcn.tinhDienTich() << " m2." <<endl; // in tong chi phi de son mau cout<< "Tong chi phi de son mau la: " << Hcn.tinhChiPhi(dientich) << " VND." <<endl; return 0; } Biên dịch và chạy chương trình C++ trên sẽ cho kết quả sau: 2. Các hình thức kế thừa 2.1. Hình thức kế thừa private Kiểu kế thừa trong C++ Khi kế thừa từ một lớp cơ sở, lớp cơ sở đó có thể được kế thừa thông qua kiểu kế thừa là public, protected hoặc private. Kiểu kế thừa trong C++ được xác định bởi Access- specifier Chúng ta hiếm khi sử d ụng kiểu kế thừa protected hoặc private, nhưng kiểu kế thừa public thì được sử dụng phổ biến hơn. Trong khi sử dụng các kiểu kế thừa khác sau. Kiểu kế thừa private: Khi kế thừa từ m ột lớp cơ s ở là private, thì các thành viên public và protected của lớp cơ sở trở thành các thành viên private của lớp kế thừa 2.2. Hình thức kế thừa Protected Kiểu kế th ừa protected: Khi kế th ừa từ m ột lớp cơ s ở là protected, thì các thành viên public và protected của lớp cơ sở trở thành các thành viên protected của lớp kế thừa 2.3. Hình thức kế thừa Public Kiểu kế thừa Public: Khi kế thừa từ m ột lớp cơ s ở là public, thì các thành viên public của lớp cơ sở trở thành các thành viên public của lớp kế thừa; và các thành viên protected của lớp có sở trở thành các thành viên protected của lớp kế thừa. Một thành viên là private của lớp cơ sở là không bao giờ có thể được truy cập trực tiếp từ một lớp kế thừa, nhưng có thể truy cập thông qua các lời gọi tới các thành viên public và protected của lớp cơ sở đó. 3. Sự trùng tên trong kế thừa Kế thừa có hay không thì bạn vẫn có thể code được thuộc tính & phương thức cho bất kì class nào. Tuy nhiên, khi câu chuyện project bắt đầu phức tạp, thì không có kế thừa sẽ khiến ta code dài và khó khăn hơn bao giờ hết. Ví dụ chúng ta đang code một hệ thống quản lý nhân viên, trong đó có class quản lý, nhân viên phòng A, phòng B và phòng C. 68