Bài giảng Lập trình hướng đối tượng và C++ - ĐH Hàng Hải
lượt xem 80
download
Phần này trình bày về một số kỹ thuật hay phương phát lập trình được phát triển để giải quyết các vấn đề trong tin học kể từ khi máy tính ra đời.
Bình luận(0) Đăng nhập để gửi bình luận!
Nội dung Text: Bài giảng Lập trình hướng đối tượng và C++ - ĐH Hàng Hải
- BỘ GIAO THÔNG VẬN TẢI TRƢỜNG ĐẠI HỌC HÀNG HẢI ́ BỘ MÔN: KHOA HỌC MAY TÍ NH KHOA: CÔNG NGHỆ THÔNG TIN BÀI GIẢNG LẬP TRÌNH HƢỚNG ĐỐI TƢỢNG VÀ C++ TÊN HỌC PHẦN : Lập trình hƣớng đối tƣợng và C++ MÃ HỌC PHẦN : 17209 TRÌNH ĐỘ ĐÀO TẠO : ĐẠI HỌC CHÍNH QUY DÙNG CHO SV NGÀNH : CÔNG NGHỆ THÔNG TIN HẢI PHÒNG - 2008
- Mô tả vắn tắt nội dung và khối lượng các học phần Tên học phần: Lập trình hướng đối tượng . Loại học phần : 3 Bộ môn phụ trách giảng dạy: Khoa học máy tính. Khoa phụ trách: CNTT Mã học phần: 15508 Tổng số TC: 3 TS tiết Lý thuyết Thực hành/ Xemina Tự học Bài tập lớn Đồ án môn học 75 45 30 0 0 0 Điều kiện tiên quyết: Sinh viên phải học và thi đạt các học phần sau mới được đăng ký học học phần này: Kỹ thuật lập trình Pascal, Kỹ thuật lập trình C. Mục tiêu của học phần: Cung cấp kiến thức của phương pháp lập trình hướng đối tượng và rèn luyện kỹ năng lập trình . Nội dung chủ yếu: - Những mở rộng của lập trình hướng đối tượng. - Đối tượng và lớp. - Đóng gói, thừa kế, đa hình. - Bản mẫu... Nội dung chi tiết: PHÂN PHỐI SỐ TIẾT TÊN CHƢƠNG MỤC TS LT Thực hành BT KT Chƣơng 1: Lâ ̣p trinh hướng đố i tươ ̣ng và ̀ 3 3 ngôn ngữ C++ 1.1 Ưu điểm của lập trình hướng đối tượng 1.2 Giới thiệu ngôn ngữ C++ Chƣơng 2: Những khái niê ̣m mở đầ u 9 6 3 2.1 Cài đặt ngôn ngữ C++ 2.2 Cấu trúc một chương trình C++ 2.3 Kiểu dữ liệu cơ sở 2.4 Quy tắc sử dụng từ khóa, tên chuẩn, tên từ đặt. 2.5 Các chỉ thị gán, so sánh, điều kiện nếu thì .. Chƣơng 3: Con trỏ, tham chiế u và hàm 6 3 3 3.1 Khai báo hàm con, hàm chính. 3.2 Quy tắc đổi kiểu dữ liệu, kiểu trỏ. 3.3 Định nghĩa chồng hàm, tham số ngầm định.. 3.5 Tham chiểu. Chƣơng 4: Các dòng vào ra trong C++ 9 5 3 1 4.1 Đối tượng vào ra cout, cin 4.2 Đẩy dòng dữ liệu lên màn hình 4.3 Nhập dòng dữ liệu từ bàn phím 4.4 Định dạng dòng dữ liệu hiển thị 4.5 Vào ra với tệp Chƣơng 5: Đối tượng và Lớp 18 8 9 1 5.1 Định nghĩa đối tượng 5.2 Khai báo lớp i
- 5.3 Hàm thiết lập, huỷ bỏ 5.4 Thành phần tĩnh, hàm bạn, lớp bạn 5.5 Định nghĩa chồng toán tử Chƣơng 6: Thừa kế 9 6 3 6.1 Lớp cơ sở, lớp dẫn xuất 6.2 Quy tắc thừa kế 6.3 Tương thích lớp cơ sở và lớp dẫn xuất 6.4 Đơn thừa kế, đa thừa kế Chƣơng 7 Ràng buộc động và Đa thể 6 3 3 7.1 Hàm ảo, ràng buộc tĩnh, động 7.2 Đa thể Chƣơng 8: Bản mẫu 12 5 6 1 8.1 Hàm bản mẫu 8.2 Ưu khuyết điểm của hàm bản mẫu 8.3 Lớp bản mẫu Chƣơng 9: Giới thiê ̣u về phân tich thiế t kế ́ 3 3 hướng đố i tươ ̣ng Nhiệm vụ của sinh viên: Lên lớp đầy đủ và chấp hành mọi quy định của Nhà trường. Tài liệu học tập: 1. Tên tác giả. Tên sách. Nhà xuất bản. Năm xuất bản. 2. Phạm Văn Ất. Kỹ thuật lập trình hướng đối tượng. NXB KHKT. 1998 3. Một số website liên quan. Hình thức và tiêu chuẩn đánh giá sinh viên: - Thi viết hoặc thi thực hành. - Sinh viên phải bảo đảm các điều kiện theo Quy chế của Nhà trường và của Bộ. Thang điểm : Thang điểm chữ A,B,C,D,F. Điểm đánh giá học phần: Z=0,3X+0,7Y. ii
- Chƣơng 1: Lâ ̣p trinh hƣớng đố i tƣơ ̣ng và ngôn ngƣ̃ C++ ̀ 1. Sƣ ̣ phát triể n của các ky ̃ thuâ ̣t lâ ̣p trinh̀ Phầ n này trinh bày về mô ̣t số kỹ thuâ ̣t hay phương pháp lâ ̣p trinh đươ ̣c phát triể n để ̀ ̀ giải quyết các vấn đề trong Tin học kể từ khi má y tính ra đời . Sự phát triể n của các kỹ thuâ ̣t lâ ̣p trình liên quan chă ̣t chẽ tới sự phát triể n phầ n cứng của máy vi tính cũng như viê ̣c ứng du ̣ng máy tinh vào giải quyế t các vấ n đề trong thực tế . Chúng ta có thể chia ́ các phương pháp lâ ̣p trinh thành các kiể u sau: ̀ Lâ ̣p trinh không có cấ u trúc ̀ Lâ ̣p trinh hướng thủ tu ̣c ̀ Lâ ̣p trinh theo kiể u module hóa ̀ Lâ ̣p trinh hướng đố i tươ ̣ng ̀ Chúng ta sẽ lần lượt xem xét các kỹ thuật lập trình này . 1.1 Lâ ̣p trinh không có cấ u trúc (hay lâ ̣p trinh tuyế n tính) ̀ ̀ Thông thường mo ̣i người bắ t đầ u ho ̣c lâ ̣p trình bằ ng cách viế t các chương trình nhỏ và đơn giản chỉ chứa một “chương trình chính” . Ở đây một chương trình chính có nghĩa là một tâ ̣p các lê ̣nh hoă ̣c câu lê ̣nh làm viê ̣c với các dữ liê ̣u toàn cu ̣c trong cả chương trinh (các biến dùng trong chương trình là các biến toàn cục ). Chúng ta có thể ̀ minh hoa ̣ bằ ng hình vẽ sau đây: Lâ ̣p trinh không có cấ u trúc. Chƣơng trinh chính ̀ ̀ thao tác trƣ̣c tiế p trên các dƣ̃ liêu toàn cu ̣c ̣ Mô ̣t số nhươ ̣c điể m của lâ ̣p trình không có cấ u trúc: Lâ ̣p trình không có cấ u trúc không có khả năng kiể m soát tính thấ y đươ ̣c của dữ liê ̣u. Mọi dữ liệu trong chương trình đều là biến toàn cục do đó có thể bị thay đổi bởi bấ t kỳ phầ n nào đó của chương trinh. ̀ Viê ̣c không kiể m soát đươ ̣c tinh thấ y đươ ̣c của dữ liê ̣u dẫn đế n các khó khăn ́ trong viê ̣c gỡ lỗi chương trinh, đă ̣c biê ̣t là các chương trinh lớn. ̀ ̀ Kỹ thuật lập trình không có cấu trúc có rất nhiều bất lợi lớn khi chương trình đủ lớn. Ví dụ nếu chúng ta cần thực hiện lại một đoạn câu lệnh trên một tập dữ liệu khác thì buộc phải copy đoạn lệnh đó tới vị trí trong chương trình mà chúng ta muố n thực hiê ̣n . Điề u này làm nảy sinh ý tưởng trich ra các đoa ̣n lê ̣nh thường ́ xuyên cầ n thực hiê ̣n đó , đă ̣t tên cho chúng và đưa ra mô ̣t kỹ thuâ ̣t cho p hép gọi và trả về các giá trị từ các thủ tục này. 1.2 Lâ ̣p trinh thủ tu ̣c hay lâ ̣p trinh có cấ u trúc ̀ ̀ Với lâ ̣p trình thủ tu ̣c hay hướng thủ tu ̣c chúng ta có thể nhóm các câu lê ̣nh thường xuyên thực hiê ̣n trong chương trình chín h la ̣i mô ̣t chỗ và đă ̣t tên đoa ̣n câu lê ̣nh đó thành một thủ tục . Mô ̣t lời go ̣i tới thủ tu ̣c sẽ đươ ̣c sử du ̣ng để thực hiê ̣n đoa ̣n câu lê ̣nh đó. Sau khi thủ tu ̣c thực hiê ̣n xong điề u khiể n trong chương trinh đươ ̣c trả về ngay sau ̀ vị trí lời gọi tới thủ tục trong chương trình chính . Với các cơ chế truyề n tham số cho 1
- thủ tục chúng ta có các chương trình con . Mô ̣t chương trình chính bao gồ m nhiề u chương trinh con và các chương trinh đươ ̣c viế t mang tinh cấ u trúc cao hơn, đồ ng thời ̀ ̀ ́ cũng ít lỗi hơn. Nế u mô ̣t chương trinh con là đúng đắ n thì kế t quả thực hiê ̣n trả về luôn ̀ đúng và chúng ta không cầ n phải quan tâm tới các chi tiế t bên trong của thủ tu ̣c . Còn nế u có lỗi chúng ta có thể thu he ̣p pha ̣m vi gỡ lỗi trong các chương trình con chưa đươ ̣c chứng minh là đúng đắ n , đây đươ ̣c xem như trừu tươ ̣ng hàm và là nề n tảng cho lâ ̣p trinh thủ tu ̣c. ̀ Mô ̣t chương trình chính với lâ ̣p trình thủ tu ̣c có thể đươ ̣c xem là tâ ̣p hơ ̣p các lời go ̣i thủ tục. Lâ ̣p trinh thủ tục. Sau khi chƣơng trinh con thƣ̣c ̀ ̀ hiên xong điề u khiể n đƣơ ̣c trả về ngay sau vi trí lời ̣ ̣ gọi tới chƣơng trình con Chương trình chính có nhiê ̣m vu ̣ truyề n các dữ liê ̣u cho các lời go ̣i cụ thể, dữ liê ̣u đươ ̣c xử lý cu ̣c bô ̣ trong chương trình con sau đó các kế t quả thực hiê ̣n này đươ ̣c trả về cho chương trinh chinh . Như vâ ̣y luồ ng dữ liê ̣u có thể đươ ̣c minh ho ̣a như là mô ̣t đồ ̀ ́ thị phân cấp, mô ̣t cây: Lâ ̣p trinh hƣớng thủ tu ̣c. Chƣơng trinh chính ̀ ̀ phố i hơ ̣p các lời go ̣i tới các thủ tu ̣c với các dƣ̃ liêu thích hơ ̣p là các tham số ̣ Lâ ̣p trình hướng thủ tu ̣c là mô ̣t kỹ thuâ ̣t lâ ̣p trình có nhiề u ưu điể m . Khái niệm chương trinh con là mô ̣t ý tưở ng rấ t hay , nó cho phép một chương trình lớn có thể ̀ đươ ̣c chia thành nhiề u chương trinh con nhỏ hơn , đo đó dễ viế t hơn và it lỗi hơn . Để ̀ ́ có thể sử dụng được các thủ tục chung hoặc một nhóm các thủ tục trong các chương trình khác, người ta đã phát minh ra mô ̣t kỹ thuâ ̣t lâ ̣p trình mới , đó là kỹ thuâ ̣t lâ ̣p trình theo kiể u module. 1.3 Lâ ̣p trinh module ̀ 2
- Trong lâ ̣p trình module các thủ tu ̣c có cùng mô ̣t chức năng chung sẽ đươ ̣c nhóm la ̣i với nhau ta ̣o thàn h mô ̣t module riêng biê ̣t . Mô ̣t chương trinh sẽ không chỉ bao gồ m ̀ mô ̣t phầ n đơn lẻ . Nó được chia thành một vài phần nhỏ hơn tương tác với nhau qua các lời gọi thủ tục và tạo thành toàn bộ chương trình. Lâ ̣p trinh module. Chƣơng trinh chính là sƣ̣ kế t hơ ̣p ̀ ̀ giƣ̃a các lời go ̣i tới các thủ tu ̣c trong các module riêng biêṭ với các dƣ̃ liêu thích hơ ̣p ̣ Mỗi module có dữ liê ̣u riêng của nó . Điề u này cho phép các module có thể kiể m soát các dữ liệu riêng của nó bằng các lời gọi tới các thủ tục trong module đó . Tuy nhiên mỗi module chỉ xuấ t hiê ̣n nhiề u nhấ t mô ̣t lầ n trong cả chương trình . Yế u điể m của lâ ̣p trinh thủ tu ̣c và lâ ̣p trinh module hóa : ̀ ̀ Khi đô ̣ phức ta ̣p của chương trinh tăng lên sự phu ̣ thu ộc của nó vào các kiểu dữ ̀ liê ̣u cơ bản mà nó xử lý cũng tăng theo . Vấ n đề trở nên rõ ràng rằ ng cấ u trúc dữ liê ̣u sử du ̣ng trong chương trình cũng quan tro ̣ng không kém các phép toán thực hiê ̣n trên chúng. Điề u này càng lô ̣ rõ khi kích thước chương trình tăng . Các kiểu dữ liê ̣u đươ ̣c xử lý nhiề u trong các thủ tu ̣c của mô ̣t chương trinh có cấ u trúc . Do đó khi ̀ thay đổ i cài đă ̣t của mô ̣t kiể u dữ liê ̣u sẽ dẫn đế n nhiề u thay đổ i trong các thủ tu ̣c sử dụng nó. Mô ̣t nhươ ̣c điể m nữa là khi cầ n dùng nhiề u nhóm làm viê ̣c để xây dựng mô ̣t chương trinh chung . Trong lâ ̣p trinh có cấ u trúc mỗi người sẽ đươ ̣c giao xây dựng ̀ ̀ mô ̣t số thủ tu ̣c và kiể u dữ liê ̣u . Những lâ ̣p trinh viên xử lý các thủ tục khác nhau ̀ nhưng la ̣i có liên quan tới các kiể u dữ liê ̣u dùng chung nên nế u mô ̣t người thay đổ i kiể u dữ liê ̣u thì sẽ làm ảnh hưởng tới công viê ̣c của nhiề u người khác , đă ̣c biê ̣t là khi có sai sót trong viê ̣c liên la ̣c giữa các thành viên của nhóm . Viê ̣c phát triể n các phầ m mề m mấ t nhiề u thời gian tâ ̣p trung xây dựng la ̣i các cấ u trúc dữ liê ̣u cơ bản . Khi xây dựng mô ̣t chương trinh mới trong lâ ̣p trinh có cấ u ̀ ̀ trúc lập trình viên thường phải xây dựng lại các cấu trúc dữ liệu cơ bản cho phù hơ ̣p với bài toán và điề u này đôi khi rấ t mấ t thời gian . 1.4 Lâ ̣p trinh hƣớng đố i tƣơ ̣ng ̀ 3
- Trong lâ ̣p trình hướng đố i tươ ̣ng trong mỗi chương trình chúng ta có mô ̣t số các đố i tươ ̣ng (object) có thể tương tác với nhau , thuô ̣c các lớp (class) khác nhau , mỗi đố i tươ ̣ng tự quản lý lấ y các dữ liê ̣u của riêng chúng. Lâ ̣p trình hướng đố i tươ ̣ng . Các đối tượng tương tác với nhau bằ ng cách gửi các thông điê ̣p. Chương trinh chinh sẽ bao gồ m mô ̣t số đố i tươ ̣ng là thể hiê ̣n (instance) của các lớp, ̀ ́ các đối tượng này tương tác với nhau thực hiện các chức năng của chương trình . Các lớp trong lâ ̣p trinh hướng đố i tươ ̣ng có thể xem như là mô ̣t sự trừu tươ ̣ng ở mức cao ̀ hơn của các cấ u trúc (struct hay record ) hay kiể u dữ liê ̣u do người dùng đinh nghiạ ̃ trong các ngôn ngữ lâ ̣p trinh có cấ u trúc với sự tich hơ ̣p cả các toán tử v à dữ liệu trên ̀ ́ các kiểu đó. Các ưu điểm của lập trình hướng đối tượng: Lâ ̣p trinh hướng đố i tươ ̣ng ra đời đã giải quyế t đươ ̣c nhiề u nhươ ̣c điể m tồ n ta ̣i ̀ trong lâ ̣p trinh có cấ u trúc . Trong lâ ̣p trinh OOP có it lỗi hơn và vi ệc gỡ lỗi cũng ̀ ̀ ́ đơn giản hơn, đồ ng thời lâ ̣p trình theo nhóm có thể thực hiê ̣n rấ t hiê ̣u quả . Ít lỗi là mô ̣t trong các ưu điể m chính của OOP vì theo thố ng kê thì viê ̣c bảo trì hê ̣ thố ng phầ n mề m sau khi giao cho người dùng chiếm tới 70% giá thành phần mềm. Viê ̣c thay đổ i các cài đă ̣t chi tiế t bên dưới trong lâ ̣p trinh OOP không làm ảnh ̀ hương tới các phầ n khác của chương trinh do đó viê ̣c mở rô ̣ng qui mô của mô ̣t ̀ chương trình dễ dàng hơn , đồ ng thời là m giảm thời gian cầ n thiế t để phát triể n phầ n mề m. Với khái niê ̣m kế thừa các lâ ̣p trinh viên có thể xây dựng các chương trinh từ ̀ ̀ các phần mềm sẵn có. OOP có tinh khả chuyể n cao . Mô ̣t chương trinh viế t trên mô ̣t hê ̣ thố ng ́ ̀ nề n (chẳ ng ha ̣n Windows ) có thể chạy trên nhiều hệ thống nền khác nhau (chẳ ng ha ̣n Linux, Unix…). OOP có hiê ̣u quả cao . Thực tế cho thấ y các hê ̣ thố ng đươ ̣c xây dựng bằ ng OOP có hiệu năng cao. 2. Mô ̣t số khái niêm cơ bản của lâ ̣p trình hƣớng đối tƣợng ̣ 1.1 Kiể u dƣ̃ liêu trƣ̀u tƣơ ̣ng ADT(Astract Data Type) ̣ 4
- Mô ̣t số người đinh nghia OOP là lâ ̣p trình với các kiể u dữ liê ̣u trừu tươ ̣ng và các ̣ ̃ mố i quan hê ̣ giữa chúng . Trong phầ n này chúng ta sẽ xem xét các kiể u dữ liê ̣u trừu tươ ̣ng như là mô ̣t khái niê ̣m cơ bản của OOP và sử du ̣ng mô ̣t số ví du ̣ để minh ho ̣a . Đinh nghia về kiể u dữ liê ̣u trừu tươ ̣ng: ̣ ̃ Mô ̣t kiể u dữ liê ̣u trừu tươ ̣ng là mô ̣t mô hình toán ho ̣c của các đố i tươ ̣ng dữ liê ̣u ta ̣o thành một kiểu dữ liệu và các toán tử (phép toán) thao tác trên các đố i tươ ̣ng đó . Chú ý là trong định nghĩa này các toán tử thao tác trên các đối tượng dữ liệu gắn liền với các đố i tươ ̣ng ta ̣o thành mô ̣t kiể u dữ liê ̣u trừu tươ ̣ng. Đặc tả về một kiểu dữ liệu trừu tượng không có bấ t kỳ mô ̣t chi tiế t cu ̣ thể nào về cài đă ̣t bên trong của kiể u dữ liê ̣u . Viê ̣c cài đă ̣t mô ̣t kiể u dữ liê ̣u trừu tươ ̣ng đòi hỏi mô ̣t quá trinh chuyể n đổ i từ đă ̣c tả của nó sang ̀ mô ̣t cài đă ̣t cu ̣ thể trên mô ̣t ngôn ngữ lâ ̣p trinh cu ̣ thể ̀ . Điề u này cho phép chúng ta phân biê ̣t các ADT với các thuâ ̣t ngữ kiể u dữ liê ̣u (data type) và cấu trúc dữ liệu (data structure). Thuâ ̣t ngữ kiể u dữ liê ̣u đề câ ̣p tới mô ̣t cài đă ̣t cu ̣ thể (có thể là kiểu built in hoă ̣c do người dùng đinh nghia ) của một mô hình toán học được đặc tả bởi một ADT . ̣ ̃ Cấ u trúc dữ liê ̣u đề câ ̣p tới mô ̣t tâ ̣p các biế n có cùng kiể u đươ ̣c gắ n kế t với nh au theo mô ̣t cách thức xác đinh nào đó . ̣ Ví dụ về kiểu dữ liệu trừu tượng: Số nguyên. Kiể u dữ liê ̣u trừu tươ ̣ng số nguyên: ADT Integer: Dƣ̃ liêu: mô ̣t tâ ̣p các chữ số và mô ̣t dấ u tiề n tố là + hoă ̣c -. Chúng ta ký hiệu cả số ̣ là N. Các toán tử: constructor: khởi ta ̣o mô ̣t số nguyên sub(k): trả về hiệu N – k. add(k): trả về tổng N + k. …… End 1.2 Đối tƣợng (Objects) và lớp (Classes) Trong mô ̣t chương trinh hướng đố i tươ ̣ng chúng ta có các đố i tươ ̣ng . Các đố i tươ ̣ng ̀ này là đại diện cho các đối tượng thực trong thực tế . Có thể coi khái niệm đối tượng trong OOP chính là các kiể u dữ liê ̣u trong các ngôn ngữ lâ ̣p trình có cấ u trúc . Mỗi mô ̣t đố i tươ ̣ng có các dữ liê ̣u riêng của nó và được gọi là các member variable hoặc là các data member . Các toán tử thao tác trên các dữ liệu này được gọi là các member function. Mỗi mô ̣t đố i tươ ̣ng là thể hiê ̣n (instance) của một lớp . Như vâ ̣y lớp là đa ̣i diê ̣n cho các đối tượng có các member function giống nhau và các data member cùng kiểu . Lớp là một sự trừu tượng hóa của khái niệm đối tượng . Tuy nhiên lớp không phải là mô ̣t ADT, nó là một cài đặt của một đặc tả ADT . Các đối tượ ng của cùng mô ̣t lớp có thể chia sẻ các dữ liê ̣u dùng chung, dữ liê ̣u kiể u này đươ ̣c go ̣i là class variable . 1.3 Kế thƣ̀a (Inheritance) Khái niệm kế thừa này sinh từ nhu cầu sử dụng lại các thành phần phần mềm để phát triển các phầ n mề m mới hoă ̣c mở rô ̣ng chức năng của phầ n mề m hiê ̣n ta ̣i . Kế thừa là một cơ chế cho phép các đối tượng của một lớp có thể truy cập tới các member variable và function của mô ̣t lớp đã đươ ̣c xây dựng trước đó mà không cầ n xây dựng lại các thành phần đó. Điề u này cho phép chúng ta có thể ta ̣o ra các lớp mới là mô ̣t mở rô ̣ng hoă ̣c cá biê ̣t hóa của mô ̣t lớp sẵn có . Lớp mới (gọi là derived class) kế thừa từ lớp 5
- cũ (gọi là lớp cơ sở base class). Các ngôn ngữ lập trình hướng đối tượng có thể hỗ trợ khái niệm đa kế thừa cho phép một lớp có thể kế thừa từ nhiều lớp cơ sở . Lớp kế thừa derived class có thể có thêm các data member mới hoă ̣c các member function mới. Thêm vào đó lớp kế thừa có thể tiế n hành đinh nghia la ̣i mô ̣t hàm của ̣ ̃ lớp cơ sở và trong trường hơ ̣p này người ta nói rằ ng lớp kế thừa đã overload hàm thành viên của lớp cơ sở. 1.4 Dynamic Binding (tạm dịch là ràng buộ c đô ̣ng) và Porlymorphism (đa xa ̣ hoă ̣c đa thể ) Chúng ta lấy một ví dụ để minh hoạ cho hai khái niệm này . Giả sử chúng ta có một lớp cơ sở là Shape , hai lớp kế thừa từ lớp Shape là Circle và Rectange . Lớp Shape là mô ̣t lớp trừ u tươ ̣ng có mô ̣t member function trừu tươ ̣ng là draw (). Hai lớp Circle và Rectange thực hiê ̣n overload la ̣i hàm draw của lớp Shape với các chi tiế t cài đă ̣t khác nhau chẳ ng ha ̣n với lớp Circle hàm draw sẽ vẽ mô ̣t vòng tròn còn với lớp Rectange thì sẽ vẽ một hình chữ nhật. Và chúng ta có một đoạn chương trình chính hợp lệ như sau : int main() { Shape shape_list[4]; int choose; int i; for(i=0;i choose; if(choose==0) { shape_list[i] = new Circle(); }else{ shape_list[i] = new Rectange(); } } for(i=0;idraw(); } } Khi biên dich chương trinh này thành mã thực hiê ̣n (file .exe) trình biên dịch không ̣ ̀ thể xác đinh đươ ̣c trong mảng shape _list thì phầ n tử nào là Circle phầ n tử nào là ̣ Rectange và do đó không thể xác đinh đươ ̣c phiên bản nào của hàm draw sẽ đươ ̣c go ̣i ̣ thực hiê ̣n. Viê ̣c go ̣i tới phiên bản nào của hàm draw để thự c hiê ̣n sẽ đươ ̣c quyế t đinh ̣ tại thời điểm thực hiện chương trình , sau khi đã biên dich và điề u này đươ ̣c go ̣i là ̣ dynamic binding hoă ̣c late binding. Ngươ ̣c la ̣i nế u viê ̣c xác đinh phiên bản nào sẽ đươ ̣c ̣ gọi thực hiện tương ứng vớ i dữ liê ̣u gắ n với nó đươ ̣c quyế t đinh ngay trong khi biên ̣ dịch thì người ta gọi đó là static binding. Ví dụ này cũng cung cấp cho chúng ta một minh họa về khả năng đa thể (polymorphism). Khái niệm đa thể được dùng để chỉ khả năng của mô ̣t thông điê ̣p có thể đươ ̣c gửi tới cho các đố i tươ ̣ng của nhiề u lớp khác nhau ta ̣i thời điể m thực hiê ̣n 6
- chương trình. Chúng ta thấy rõ lời gọi tới hàm draw sẽ được gửi tới cho các đối tượng của hai lớp Circle và Rectange ta ̣i thời điể m chương trinh đươ ̣c thực hiê ̣n. ̀ Ngoài các khái niệm cơ bản trên OOP còn có thêm một số khái niệm khác chẳng hạn như name space và exception handling nhưng không phải là các khái niệm bản chấ t. 3. Ngôn ngƣ̃ lâ ̣p trinh C++ và OOP. ̀ Giố ng như bấ t kỳ mô ̣t ngôn ngữ nào của con người , mô ̣t ngôn ngữ lâ ̣p trình là phương tiê ̣n để diễn tả các khái niê ̣m , ý tưởng. Viê ̣c phát triể n các chương trình hay phầ n mề m là quá trinh mô hinh hóa các t rạng thái tự nhiên của thế giới thực và xây ̀ ̀ dựng các chương trinh dựa trên các mô hinh đó . ̀ ̀ Các chương trình thực hiện chức năng mô tả phương pháp cài đặt của mô hình . Các thế hệ ngôn ngữ lập trình: Có thể phân chia các thế hê ̣ ngôn ngữ lâ ̣p trình thành 4 thế hê ̣: 1: vào năm 1954 – 1958 (Fortran I) với đă ̣c điể m là các biể u thức toán ho ̣c 2: vào năm 1959 – 1961 (Fortran II, Cobol) với các thủ tu ̣c 3: vào những năm 1962 – 1970 (Pascal, Simula) với đă ̣c trưng là các khố i , các lớp… 4: đang phát triể n chưa có dẫn chứng thực tế . Các ngôn ngữ này ngày càng cách xa ngôn ngữ máy và các trình biên dịch của chúng ngày càng phải làm việc nhiều hơn . 1.1 Sƣ ̣ phát triể n của các ngôn ngữ lập trình hƣớng đối tƣợng 1967 Simula 1970 to 1983 Smalltalk 1979 Common LISP Object System 1980 Stroustrup starts on C++ 1981 Byte Smalltalk issue 1983 Objective C 1986 C++ 1987 Actor, Eiffel 1991 C++ release 3.0 1995 Java 1983 to 1989 Language books with OO concepts 1989 to 1992 Object-oriented design books 1992 to present Object-oriented methodology books Các ngôn ngữ lập trình khác Java Self Python Perl Prograph 7
- Modula 3 Oberon Smalltalk Venders ParcPlace, Digitalk, Quasar Prolog++ Ada 9X Object Pascal (Delphi) Object X, X = fortran, cobal, etc. C#. Như vâ ̣y là có rấ t nhiề u ngôn ngữ lâ ̣p trinh hướng đố i tươ ̣ng đã ra đời và chiế m ưu ̀ thế trong số chúng là C++ và Java. Mỗi ngôn ngữ đề u có đă ̣c điể m riêng của nó và thích hợp với các lĩnh vực khác nhau nhưng có lẽ C++ là ngôn ngữ cài đặt nhiều đặc điể m của OOP nhấ t . 1.2 Ngôn ngƣ̃ lâ ̣p trinh C++. ̀ C++ là một ngôn ngữ lập trình hướng đối tượng được Bjarne Stroustrup (AT & T Bell Lab) (giải thưởng ACM Grace Murray Hopper năm 1994) phát triển từ ngôn ngữ C. C++ kế thừa cú pháp và mô ̣t số đă ̣c điể m ưu viê ̣t của C : ví dụ như xử lý con trỏ , thư viê ̣n các hàm phong phú đa da ̣ng , tính khả chuyển cao , chương trình cha ̣y nhanh …. Tuy nhiên về bản chấ t thì C ++ khác hoàn toàn so với C , điề u này là do C ++ là một ngôn ngữ lâ ̣p trinh hướng đố i tươ ̣ng. ̀ Chƣơng 2: Nhƣ̃ng khái niêm mở đầ ụ 1. Chƣơng trinh đầ u tiên ̀ 1.1 Quá trình biên dịch một chƣơng trinh C++ ̀ Tấ t cả các ngôn ngữ trên máy tính đề u đươ ̣c dich từ mô ̣t da ̣ng nào đó mà con người ̣ có thể hiểu được một cách dễ dàng (các file mã nguồn được viết bằng một ngôn ngữ bâ ̣c cao) sang da ̣ng có thể thực hiê ̣n đươ ̣c trên máy tinh (các lệnh dưới dạng ngôn ngữ ́ máy). Các chương trình thực hiện quá trình này chia thành hai dạng được gọi tên là các trình thông dịch (interpreter) và các trình biên dịch (compiler). Trình thông dịch : Mô ̣t trinh t hông dich sẽ dich mã nguồ n thành các hành đô ̣ng ̀ ̣ ̣ (activity), các hành động này có thể bao gồm một nhóm các lệnh máy và tiến hành thực hiê ̣n ngay lâ ̣p tức các hành đô ̣ng này . Ví dụ như BASIC là một ngôn ngữ điển hình cho cá c ngôn ngữ thông dich . BASIC cổ điể n thông dich từng dòng lê ̣nh thực ̣ ̣ hiê ̣n và sau đó quên ngay lâ ̣p tức dòng lê ̣nh vừa thông dich ̣ . Điề u này làm cho quá trình thực hiện cả một chương trình chậm vì bộ thông dịch phải tiến hành dịch lại các đoa ̣n mã trùng lă ̣p . BASIC ngày nay đã thêm vào qúa trinh biên dich để cải thiê ̣n tố c ̀ ̣ đô ̣ của chương trình. Các bộ thông dịch hiện đại chẳng hạn như Python , tiế n hành dich ̣ toàn bộ chương trình qua một ngôn ngữ trung gian sau đó thực hiê ̣n bằ ng mô ̣t bô ̣ thông dịch nhanh hơn rất nhiều. Các ngôn ngữ làm việc theo kiểu thông dịch thường có một số hạn chế nhất định khi xây dựng các dự án lớn (Có lẽ chỉ duy nhất Python là một ngoại lệ ). Bô ̣ thông dich ̣ cầ n phải luôn đươ ̣c lưu trong bô ̣ nhớ để thực hiê ̣n các mã chương trinh , và thậm chí ̀ ngay cả bô ̣ thông dich có tố c đô ̣ nhanh nhấ t cũng không thể cải thiê ̣n đươ ̣c hoàn toàn ̣ các hạn chế tốc độ .Hầ u hế t các bô ̣ thô ng dich đề u yêu cầ u toàn bô ̣ mã nguồ n cầ n phải ̣ đươ ̣c thông dich mô ̣t lầ n duy nhấ t . Điề u này không những dẫn đế n các ha ̣n chế về kích ̣ 8
- thước của chương trình mà còn ta ̣o ra các lỗi rấ t khó gỡ rố i nế u như ngôn ngữ không cung cấp các công cụ hiệu quả để xác định hiệu ứng của các đoạn mã khác nhau . Trình biên dịch : Mô ̣t trinh biên dich dich mã nguồ n trực tiế p thành ngôn ngữ ̀ ̣ ̣ assembly hoă ̣c các lê ̣nh máy . Kế t quả cuố i cùng là mô ̣t file duy nhấ t hoă ̣c các file chứa các mã máy. Đây là mô ̣t quá trình phức ta ̣p và đòi hỏi mô ̣t vài bước . Quá trình chuyển đổ i từ mã chương trinh ban đầ u thành mã thực hiê ̣n là tương đố i dài đố i với mô ̣t trinh ̀ ̀ biên dich. ̣ Tùy thuộc vào sự n hạy cảm của người viết trình biên dịch , các chương trình sinh ra bởi mô ̣t trình biên dich có xu hướng đòi hỏi ít bô ̣ nhớ hơn khi thực hiê ̣n ̣ , và chúng chạy nhanh hơn rất nhiều . Mă ̣c dù kich thước và tố c đô ̣ thường là các lý do hàng đầ u ́ cho viê ̣c sử du ̣ng mô ̣t trinh biên dich , trong rấ t nhiề u trường hơ ̣p đây không phải là các ̀ ̣ lý do quan trọng nhất . Mô ̣t vài ngôn ngữ (chẳ ng ha ̣n như C ) đươ ̣c thiế t kế để các phầ n tách biệt của một chương trình có thể đươ ̣c biên dich đô ̣c lâ ̣p hoàn toàn với nhau . Các ̣ phầ n này sau đó thâ ̣m chí có thể kế t hơ ̣p thành mô ̣t chương trinh thực hiê ̣n cuố i cùng ̀ duy nhấ t bởi mô ̣t công cu ̣ có tên là trinh liên kế t ̀ . Quá trình này gọi là separate compilation (biên dich đô ̣c lâ ̣p). ̣ Biên dich đô ̣c lâ ̣p có rấ t nhiề u điể m lơ ̣i . Mô ̣t chương trinh nế u dich ngay lâ ̣p tức ̣ ̀ ̣ toàn bộ sẽ vượt quá các giới hạn của trình biên dịch hay môi trường biên dịch có thể đươ ̣c biên dich theo từng phầ n . Các chương trình có thể được xây dựng và kiểm thử ̣ từng phầ n mô ̣t. Nế u mo ̣t phầ n nào đó đã làm viê ̣c đúng đắ n nó có thể đươ ̣c lưu la ̣i như là một khối đã hoàn thành . Tâ ̣p các phầ n đã làm viê ̣c và đươ ̣c kiể m thử có thể kế t hơ ̣p lại với nhau tạo thành các thư viện để các lập trình viên khác có thể sử dụng . Các đặc điể m này hỗ trơ ̣ cho viê ̣c ta ̣o ra các chương trình lớn . Các đặc điểm gỡ lỗi của trình biên dịch đã cải tiến một cách đáng kể qua thời gian. Các trình biên dịch đầu tiên chỉ sinh ra mã máy , và lập trình viên phải chèn các câu lê ̣nh in vào để xem thực sự chương trinh đang làm gì . Điề u này không phải lúc nào ̀ cũng hiệu quả. Các trình biên dịch hi ện đại có thể chèn các thông tin về mã nguồn vào mã thực hiện của chương trình . Thông tin này sẽ đươ ̣c sử du ̣ng bởi các bô ̣ gỡ lỗi cấ p đô ̣ nguồ n đầ y năng lực để chỉ ra chinh xác điề u gì đang diễn ra trong mô ̣t chương trinh ́ ̀ bằ ng cách theo dấ u (tracing) quá trình thực hiện của nó qua toàn bộ mã nguồn. Mô ̣t vài trình biên dich giải quyế t vấ n đề tố c đô ̣ biên dich bằ ng cách thực hiê ̣n quá ̣ ̣ trình biên dịch trong bộ nhớ (in-memory compilation). Các tr ình biên dịch theo kiểu này lưu trình biên dịch trong bộ nhớ RAM . Đối với các chương trình nhỏ , quá trình này có thể xem như là một trình thông dịch . Quá trình biên dịch Để lâ ̣p trinh bằ ng C và C ++ chúng ta cần phải hiểu c ác bước và các công cụ trong ̀ quá trình biên dịch . Mô ̣t vài ngôn ngữ (đă ̣c biê ̣t là C và C ++) bắ t đầ u thực hiê ̣n quá trình biên dịch bằng cách chạy một bộ tiền xử lý đối với mã nguồn . Bô ̣ tiề n xử lý là mô ̣t chương trinh đơ n giản thay thế các mẫu trong mã nguồ n bằ ng các mẫu khác mà ̀ các lập trình viên đã định nghĩa (sử du ̣ng các chỉ thi ̣tiề n xử lý : preprocessor directives). Các chỉ thị tiền xử lý được sử dụng để tiết kiệm việc gõ các đoạ n chương trình thường xuyên sử dụng và tăng khả năng dễ đọc cho mã nguồn . Tuy nhiên các chỉ thị tiền xử lý này đôi khi cũng gây ra những lỗi rất tinh vi và khó phát hiện . Mã sinh ra bởi bô ̣ tiề n xử lý này thường đươ ̣c ghi lên mô ̣t file ta ̣m. Các trình biên dịch thường thực hiện công việc của nó theo hai pha . Đầu tiên là phân tích mã tiề n xử lý . Bô ̣ biên dich chia mã tiề n xử lý thành các đơn vi ̣nhỏ và tổ ̣ 9
- chức chúng thành mô ̣t cấ u trúc go ̣i là cây. Ví dụ như trong biểu thức : “A+B” các phầ n tử “A”, “+”, “B” sẽ đươ ̣c lưu trên nút của cây phân tich . ́ Mô ̣t bô ̣ tới ưu hóa toàn cu ̣c (global optimizer) đôi khi cũng đươ ̣c sử du ̣ng để ta ̣o ra mã chương trình nhỏ hơn, nhanh hơn. Trong pha thứ hai , bô ̣ sinh mã duyê ̣t qua cây phân tích và sinh ra hoă ̣c là mã assemble hoă ̣c mã máy cho các nút của cây . Nế u như bô ̣ sinh mã ta ̣o ra mã assembly , thì sau đó chương trình dịch mã assembler sẽ thực hiện công việc tiếp theo . Kế t quả của hai trường hợp trên đều là một module object (mô ̣t file thường có đuôi là .o hoă ̣c .obj). Sau đó mô ̣t bô ̣ tố i ưu hoá nhỏ (peep-hole) sẽ được sử dụng để loại bỏ các đoạn chứa các câu lê ̣nh assembly thừa. Viê ̣c sử du ̣n g từ “object” để mô tả các đoa ̣n mã máy là mô ̣t thực tế không đúng lắ m. Từ này đã đươ ̣c dùng trước cả khi lâ ̣p trình hướng đố i tươ ̣ng ra đời . Từ “object” đươ ̣c sử du ̣ng có ý nghia như là từ “goal” khi nói về viê ̣c biên dich , trong khi đó trong ̃ ̣ lâ ̣p trinh hướng đố i tươ ̣ng nó la ̣i có nghia là “a thing with boundaries”. ̀ ̃ Trình liên kết kết hợp một danh sách các module object thành một chương trình thực hiê ̣n có thể na ̣p vào bô ̣ nhớ và thực hiê ̣n bởi hê ̣ đ iề u hành. Khi mô ̣t hàm trong mô ̣t module object ta ̣o ra mô ̣t tham chiế u tới mô ̣t hàm hoă ̣c mô ̣t biế n trong mô ̣t module object khác, trình liên kết sẽ sắp xếp lại các tham chiếu này ; điề u này đảm bảo rằ ng tấ t cả các hàm và dữ liệ u external đươ ̣c sử du ̣ng trong quá trình biên dich là đề u tồ n ta ̣i . ̣ Trình liên kết cũng thêm vào các module object đặc biệt để thực hiện các hành động khởi đô ̣ng. Trình liên kết có thể tìm kiếm trên các file đặc biệt gọi là các thư viện để sắp xếp lại tất cả các tham chiếu tới chúng . Mỗi thư viê ̣n chứa mô ̣t tâ ̣p các module object trong mô ̣t file. Mô ̣t thư viê ̣n đươ ̣c ta ̣o ra và bảo trì bởi mô ̣t lâ ̣p trình viên có tên là librarian. Kiể m tra kiể u tinh ̃ Trình biên dịch thực hiện kiểm tra kiểu trong pha đầu tiên của quá trình biên dịch . Quá trình kiểm tra này thực hiện kiểm thử việc sử dụng các tham số của các hàm và ngăn chă ̣n rấ t nhiề u lỗi lâ ̣p trinh khác nhau . Vì quá trình kiểm tra kiểu được thực hiện ̀ trong qúa trinh biên dich chứ không phải trong quá trinh chương trinh thực hiê ̣n nên nó ̀ ̣ ̀ ̀ đươ ̣c go ̣i là kiể m tra kiể u tinh. ̃ Mô ̣t vài ngôn ngữ lâ ̣p trinh hướng đố i tươ ̣ng (Java chẳ ng ha ̣n ) thực hiê ̣n kiể m tra ̀ kiể u ta ̣i thời điể m chương trinh cha ̣y (dynamic type checking). Nế u kế t hơ ̣p cả viê ̣c ̀ kiể m tra kiể u tinh và đô ̣ng thì sẽ hiê ̣u quả hơn nhưng kiể m tra kiể u đô ̣ng cũng làm cho ̃ chương trình thực hiê ̣n bi ̣ảnh hưởng đôi chú t. C++ sử du ̣ng kiể m tra kiể u tinh. Kiể m tra kiể u tinh báo cho lâ ̣p trinh viên về các lỗi ̃ ̃ ̀ về sử du ̣ng sai kiể u dữ liê ̣u trong quá trinh biên dich , và do đó tối ưu hóa tốc độ thực ̀ ̣ hiê ̣n chương trinh . Khi ho ̣c C ++ chúng ta sẽ th ấy hầu hết các quyết định thiết kế của ̀ ngôn ngữ đề u tâ ̣p trung vào củng cố các đă ̣c điể m : tố c đô ̣ nhanh, hướng đố i tươ ̣ng, các đă ̣c điể m mà đã làm cho ngôn ngữ C trở nên nổ i tiế ng . Chúng ta có thể không dùng tùy chọn kiểm tra kiể u tinh của C ++ hoă ̣c cũng có thể ̃ thực hiê ̣n viê ̣c kiể m tra kiể u đô ̣ng - chỉ cần viết thêm mã. Các công cụ cho việc biên dịch độc lập Viê ̣c biên dich đô ̣c lâ ̣p rấ t cầ n thiế t nhấ t là đố i với các dự án lớn . Trong ngôn ngữ ̣ C và C ++, mô ̣t lâ ̣p trình viên có thể ta ̣o ra các đoa ̣n chương trình nhỏ dễ quản lý và đươ ̣c kiể m thử đô ̣c lâ ̣p . Công cu ̣ cơ bản để chia mô ̣t chương trình thành các phầ n nhỏ là khả năng tạo ra các thay thế được đặt tên hay là các chương trình con . Trong C và 10
- C++ mô ̣t chương trình con đươ ̣c go ̣i là mô ̣t hàm , và các hàm là các đoạn mã có thể đươ ̣c thay thế trong các file khác nhau , cho phép thực hiê ̣n quá trinh biên dich đô ̣c lâ ̣p . ̀ ̣ Nói một cách khác c ác hàm là các đơn vị nguyên tử của mã nguồn , vì chúng ta không thể đă ̣t các phầ n khác nhau của hàm trong các file khác nhau nên nô ̣i dung của mô ̣t hàm cần phải được đặt hoàn toàn trong một file (mă ̣c dù các file có thể chứa nhiề u hơn 1 hàm). Khi chúng ta go ̣i đế n mô ̣t hàm , chúng ta thường truyền cho nó một vài tham số , đó là các giá trị mà chúng ta muốn hàm làm việc với khi nó thực hiện . Khi hàm thực hiê ̣n xong chúng ta thường nhâ ̣n đươ ̣c mô ̣t giá trị trả về , mô ̣t gía tri ̣mà hàm trả la ̣i như là mô ̣t kế t quả . Cũng có thể viết các hàm không nhận các tham số và không trả về bất kỳ giá trị nào. Để ta ̣o ra mô ̣t chương trình với nhiề u file , các hàm trong một file ph ải truy cập tới các hàm và dữ liệu trong các file khác . Khi biên dich mô ̣t file , trình biên dịch C hoặc ̣ C++ phải biết về các hàm và dữ liệu trong các file khác đặc biệt là tên và cách dùng chúng. Trình biên dịch đảm bảo c ác hàm và dữ liệu được sử dụng đúng đắn . Qúa trình báo cho trình biên dịch tên và nguyên mẫu của các hàm và dữ liệu bên ngoài được gọi là khai báo (declaration). Khi chúng ta đã khai báo mô ̣t hàm hoă ̣c biế n trinh biên dic̣ h ̀ sẽ biết cách thức kiểm tra để đảm bảo các hàm và dữ liệu này được sử dụng đúng đắn . Including các file Header Hầ u hế t các thư viê ̣n đề u chứa mô ̣t số lươ ̣ng đáng kể các hàm và biế n . Để tiế t kiê ̣m công sức và đảm bảo sự nhấ t quán khi khai báo ngoài các phầ n tử này , C và C++ đã sử dụng một loại file được gọi là file header. Mỗi file header là mô ̣t file chứa các khai báo ngoài cho 1 thư viê ̣n; theo qui ước các file này có phầ n mở rô ̣ng là .h, nhưng chúng ta cũng có thể dùng các đuôi file khác cho chúng chẳng hạn như .hpp hoă ̣c .hxx. Lâ ̣p trinh viên ta ̣o ra các file thư viê ̣n sẽ cung cấ p các header file . Để khai báo các ̀ hàm và các biến bên ngoài thư viện người dùng đ ơn giản chỉ cầ n thực hiê ̣n include file header đó. Để include mô ̣t file header chúng ta sử du ̣ng chỉ thi ̣tiề n xử lý #include. Chỉ thị này sẽ báo cho bộ xử lý mở file header có tên tương ứng và chèn nội dung của file đó vào chỗ mà chỉ thị #include đươ ̣c sử du ̣ng . Tên file sử du ̣ng sau chỉ thi ̣ #include có thể nằ m giữa hai dấ u < và > hoă ̣c giữa hai dấ u “. Ví dụ: #include Nế u chúng ta sử du ̣ng chỉ thi ̣include theo cách trên thì bô ̣ tiề n xử lý sẽ tìm file header theo cách đă ̣c thù đố i với cài đă ̣t của chúng ta , nhưng thường thì sẽ có mô ̣t vài đường dẫn mà chúng ta chỉ đinh cu ̣ thể trong biế n môi trường của trình biên dich hoă ̣c ̣ ̣ trên dòng lê ̣nh để sử du ̣ng cho viê ̣c t ìm các file header . Cơ chế thiế t lâ ̣p các đường dẫn này phụ thuộc vào trình biên dịch và môi trường mà chúng ta làm việc . Ví dụ: #include “header.h” Chỉ thị tiền xử lý như trên thường có ý nghĩa là báo cho bộ tiền xử lý tìm file tương ứng trong thư mục hiện tại trước nếu không thấy thì sẽ tìm giống như trong trường hợp tên file include đươ ̣c đă ̣t giữa hai dấ u < và >. Nói chung thì đối với các file include chuẩn hoặc được sử dụng nhiều chúng ta nên đă ̣c nó trong thư mu ̣c mă ̣c đinh là include dưới thư mu ̣c cài đă ̣t trình biên dich và dùng ̣ ̣ chỉ thị theo kiểu , còn đối với các file đặc thù với ứng dụng cụ thể thì dùng kiểu tên file đă ̣t giữa hai dấ u “”. Trong quá trìn h phát triể n của C ++ các nhà cung cấp các trình biên dịch có các qui ước đặt tên khác nhau và các hệ điều hành lại có các hạn chế tên khác nhau đặc biệt là đô ̣ dài của tên file . Các vấn đề này gây ra các vấn đề về tín h khả chuyể n của chương 11
- trình. Để khắ c phu ̣c vấ n đề này người ta đã sử du ̣ng mô ̣t đinh da ̣ng chuẩ n cho phép các ̣ tên file header có thể dài hơn 8 ký tự và bỏ đi phần tên mở rộng. Để phân biê ̣t mô ̣t chương trinh C và C ++ đôi khi người ta còn dùng cách thêm mô ̣t ̀ ký tự “c” vào trước tên của các file header , chi tiế t này cũng đươ ̣c chấ p nhâ ̣n đố i với C và C++. Quá trình liên kết Trình liên kết tập hợp các module object (thườ ng là các file có phầ n mở rô ̣ ng là .o hoă ̣c .obj), đươ ̣c sinh ra bởi trình biên dich , thành một chương trình có thể thực hiện ̣ đươ ̣c và hê ̣ điề u hành có thể na ̣p vào bô ̣ nhớ và cha ̣y . Đây là pha cuố i cùng trong quá trình biên dịch. Các đặc điểm của các tr ình liên kết thay đổi phụ thuộc vào các hệ thống khác nhau . Nói chung chúng ta chỉ cần chỉ rõ cho trình liên kết biết tên của các module object và các thư viện mà chúng ta muốn liên kết , và tên của chương trình khả chạy cuố i cùng. Mô ̣t vài hê ̣ thố ng đòi hỏi chúng ta cầ n phải tự go ̣i tới các trinh liên kế t . Tuy nhiên hầ u ̀ hế t các trình biên dich hoàn chỉnh đề u thực hiê ̣n hô ̣ chúng ta công viê ̣c này . ̣ Sƣ̉ du ̣ng các thƣ viên ̣ Giờ đây chúng ta đã biế t các thuâ ̣t ngữ cơ bản , chúng ta có thể hiểu cách thức sử dụng một thư viện. Để sử du ̣ng mô ̣t thư viê ̣n cầ n phải : Include file header của thư viê ̣n Sử du ̣ng các hàm và các biế n trong thư viê ̣n Liên kế t thư viê ̣n vào chương trình khả chạy cuối cùng Các bước này cũng đúng với các module object không có trong các thư viện . Including mô ̣t file header và liên kế t các module object là các bước cơ bản để thực hiê ̣n viê ̣c biên dich đô ̣c lâ ̣p trong C và C++. ̣ Trình liên kế t làm thế nào để tim mô ̣t file thƣ viên ̀ ̣ Khi chúng ta ta ̣o ra mô ̣t tham chiế u ngoài tới mô ̣t hàm số hoă ̣c mô ̣t biế n số trong C hoă ̣c C ++, trình liên kết , khi bắ t gă ̣p tham chiế u này , có thể thực hiện một trong hai viê ̣c sa u: nế u nó chưa thấ y phầ n đinh nghia của hàm hay biế n này , nó sẽ thêm định ̣ ̃ danh vào danh sách các tham chiế u chưa đươ ̣c đinh nghia của nó . Nế u như trinh liên ̣ ̃ ̀ kế t đã bắ t gă ̣p đinh nghia của tham chiế u đó , tham chiế u sẽ đươ ̣c sắ p xế p la ̣i. ̣ ̃ Nế u như trình liên kế t không tìm thấ y đinh nghia của tham chiế u trong danh sách ̣ ̃ các module object nó sẽ tiến hành tìm kiếm trong các thư viện . Các thư viện có một vài loại chỉ số nên trình liên kết không cần th iế t phải tim kiế m hế t trong các module ̀ objetc của thư viê ̣n – nó chỉ cần xem xét các phần chỉ mục . Khi trình liên kế t tìm thấ y mô ̣t đinh nghia trong mô ̣t thư viê ̣n , toàn bộ module object chứ không chỉ phần định ̣ ̃ nghĩa của hàm , sẽ được liên kết vào chương trình thực hiện . Chú ý rằng toàn bộ thư viê ̣n sẽ không đươ ̣c liên kế t , chỉ có phần định nghĩa mà chương trình tham chiếu tới . Như vâ ̣y nế u chúng ta muố n tố i ưu về kích thước của chương trình chún g ta có thể cho mỗi hàm vào mô ̣t file khi xây dựng các thư viê ̣n riêng của mình . Điề u này đòi hỏi công sức edit nhiề u hơn nhưng cũng có thể có ich. ́ Vì trình liên kết tìm kiếm các file theo thứ tự chúng ta có thể che đi sự tồ n ta ̣i của mô ̣t hàm thư viê ̣n bằ ng cách dùng hàm của chúng ta với phầ n đinh nghia và prototype ̣ ̃ y hê ̣t như hàm thư viê ̣n . Tuy nhiên điề u này cũng có thế gây ra các lỗi mà chúng ta không thể kiể m soát đươ ̣c. 12
- Khi mô ̣t chương trình khả chạy được viết bằng C hoặc C ++ đươ ̣c ta ̣o ra, mô ̣t số các thành phần nhất định sẽ được liên kết với nó một cách bí mật . Mô ̣t trong các thành phầ n này chinh là module khởi đô ̣ng (startup), module này chứa các thủ tu ̣c khở i ta ̣o ́ cầ n phải đươ ̣c thực hiê ̣n bấ t cứ khi nào mô ̣t chương trình C hay C ++ bắ t đầ u cha ̣y. Các thủ tục này thiết lập stack và các biến khởi tạo nhất định trong chương trình . Trình biên dịch luôn thực hiện việc tìm kiếm trong các thư viện chuẩn để thực hiện liên kế t các hàm chuẩ n mà chúng ta dùng trong chương trinh nên để dùng các hàm ̀ trong các thư viê ̣n chuẩ n chúng ta đơn giản chỉ cầ n include file header của thư viê ̣n đó . Còn đối với các thư viện riêng do chúng ta ta ̣o ra chúng ta cầ n chỉ rõ tên thư viê ̣n cho trình liên kết (chẳ ng ha ̣n thư viê ̣n graphics không phải là mô ̣t thư viê ̣n chuẩ n ). 1.2 Chƣơng trinh đầ u tiên. ̀ Cách tốt nhất để học lập trình là xem các chƣơng trình của n gƣời khác viế t và học tập các kỹ thuật lập trình của họ . Sau đây là chƣơng trinh HelloWorld đƣơ ̣c ̀ viế t bằ ng C++, mô ̣t chƣơng trinh mà hầ u hế t các sách lâ ̣p trinh đều lấ y làm ví du ̣ ̀ ̀ mở đầ u. // Chương trìh HelloWorld n // File hello.cpp // In ra mà hìh xâu “Hello, World!” n n #include // Khai bá luồg cout đểsử o n dụng int main() { cout
- hạn ở đây chúng ta include file header iostream là vì cần sử dụng đối tượng cout trong thư viê ̣n iostream. Tiế p theo là hàm main () có kiểu trả về là int và không nhận tham số nào . Giố ng như C tấ t cả các chương trình C ++ đều có một và duy nhất một hàm main () và nếu chúng ta không nói gì có nghĩa là hàm main sẽ trả về m ột giá trị có kiểu int nên để tránh một vài rắc rối chúng ta nên xác định kiểu của hàm main là int và trả về 0 trước khi kế t thúc hàm . Prototype của hàm main là : int main () có nghĩa là hàm này có thể nhâ ̣n bấ t bao nhiêu tham số tuỳ ý . Trong câu lê ̣nh tiế p theo chúng ta sử du ̣ng đố i tươ ̣ng cout (console output) để in ra mô ̣t loa ̣t các tham số thông qua các toán tử “
- muố n ngay lâ ̣p tức đinh nghia biế n đó ). Để giải quyết trường hợp này chúng ta sẽ dùng ̣ ̃ từ khóa extern, ví dụ: extern int a; Khai báo này sẽ báo cho trình biên dich biế t rằ ng biế n có tên là a là tồ n ta ̣i và nó đã ̣ hoă ̣c sẽ đươ ̣c đinh nghia đâu đó trong chương trình. ̣ ̃ Ví dụ: // file: Declare.cpp // Ví dụ khai báo và định nghĩa biến extern int i; // khai bá vàkhông địh nghĩ o n a float b; // khai bá vàđịh nghĩo n a int i; // địh nghĩ biế i n a n int main() { b = 1.0; i = 2; } Các biến có thể đư ợc khai báo ở bất kỳ một vị trí nào trong chương trình , điề u này có đôi chút khác biệt so với các chương trình C. 2.2 Tầ m hoa ̣t đô ̣ng của các biế n Khái niệm tầm hoạt động của các biến cho chúng ta biết khu vực (phầ n chương trình) mà một biến nào đó có thể được sử dụng hợp lệ và khu vực nào thì việc truy cập tới mô ̣t biế n là không hơ ̣p lê .̣ Tầ m hoa ̣t đô ̣ng của mô ̣t biế n bắ t đầ u từ vi ̣trí mà nó đươ ̣c khai báo cho tới dấ u “ }” đầ u tiên khớp vớ i dấ u “ {“ ngay trước khai báo của biế n đó . Có nghĩa là tầm hoạt động của một biến được xác định là trong cặp “ {“ và “ }” gầ n nhấ t bao nó. Tấ t nhiên tầ m hoa ̣t đô ̣ng của các biế n có thể chồ ng lên nhau . 2.3 Khai báo biế n ngay trong cú pháp của các câu lênh điều khiể n ̣ Như chúng ta đã biế t trong các chương trình C ++ viê ̣c khai báo biế n là khá tự do . Các biến có thể được khai báo ở bất kỳ vị trí hợp lệ nào của chương trình miễn là chúng phải là xác định trước khi được sử dụng. Trong ngôn ngữ C và hầ u hế t các ngôn ngữ thủ tu ̣c khác lâ ̣p trinh viên bắ t buô ̣c ̀ phải khai báo các biến tại phần đầu tiên của mỗi thủ tục . Do đó khi đo ̣c các file mã nguồ n C chúng ta luôn thấ y mô ̣t loa ̣t khai báo các biế n sẽ đươ ̣c dùng mỗi thủ tu ̣c ở phầ n đầ u của thủ tu ̣c. Điề u này sẽ rấ t bấ t tiê ̣n khi mô ̣t thủ tu ̣c có nhiề u biế n hoă ̣c dài vì viê ̣c kiể m soát biế n (tên, giá trị khởi tạo, tầ m hoa ̣t) sẽ trở nên khó khăn. Đi xa hơn cả viê ̣c cho phép khai báo bấ t kỳ vi ̣trí nào hơ ̣p lê ̣ trong chương trình C++ còn cho phép khai báo và khởi tạo các biến ngay bên trong biểu thức điều khiển của các vòng lặp for, while, do hoă ̣c trong câu lê ̣nh if, switch. Ví dụ: for(int i=0;i
- switch(int i=cin.get()){ case „A‟: …; break; ….. } Mă ̣c dù vâ ̣y viê ̣c khai báo như trên chỉ thường đươ ̣c dùng với cá c vòng lă ̣p for vì đôi khi nó gây ra mô ̣t số lỗi . Ví dụ câu lệnh: while( (char c = cin.get()) !=‟q‟ ){ } sẽ làm chúng ta ngạc nhiên với kết quả nhận được . Vì toán tử != có độ ưu tiên cao hơn toán tử gán = nên c sẽ nhâ ̣n mô ̣t giá trị có kiểu Bool và sau đó mới được convert sang kiể u char. 2.4 Các kiểu biến Biế n toàn cu ̣c (global variable) Các biến toàn cục được định nghĩa bên ngoài tất cả các hàm và có thể được sử dụng trong tất cả các phần của chươ ng trình (thâ ̣m chí ngay cả phầ n chương trình nằ m trong mô ̣t file mã nguồ n khác ). Các biến toàn cục không bị ảnh hưởng bởi các tầm hoạt động (chúng tồn tại cho tới khi chương trình kết thúc). Khi cầ n tham chiế u tới các biế n toàn cu ̣c trong mô ̣t file mà nó chưa đươ ̣c khai báo (biế n này đươ ̣c khai báo trong mô ̣t file khác ) chúng ta sử dụng từ khóa extern để chỉ ra rằ ng biế n đó là mô ̣t biế n toàn cu ̣c đươ ̣c khai báo trong file khác . Biế n cu ̣c bô ̣ (hay đia phƣơng, local) ̣ Các biến địa phương thường được khai báo trong một phạm vi hay tầm hoạt động nhấ t đinh, thường là trong mô ̣t hàm . Các biến địa phương này còn được gọi là các biến ̣ tự đô ̣ng vì chúng ta có thể sử du ̣ng chúng một cách tự nhiên trong tầm hoạt động của chúng và bản thân chúng cũng tự động “out of scope” bên ngoài phạm vi hoạt động . Chúng ta có thể sử dụng từ khóa auto để làm rõ hơn điều này. Biế n thanh ghi (register variable) Các biến thanh ghi là một loại biến cục bộ . Để khai báo các biế n thanh nghi chúng ta dùng từ khóa register. Mục đích của việc khai báo các biến register là báo cho trình biên dich biế t để nó có thể làm cho viê ̣c truy câ ̣ p vào các biế n này với tố c đô ̣ càng ̣ nhanh càng tố t . Viê ̣c tăng tố c đô ̣ truy câ ̣p biế n là phu ̣ thuô ̣c vào cài đă ̣t tuy nhiên như ngụ ý của từ register điều này thường được thực hiện bằng cách đặt biến vào một thanh ghi. Không có gì đảm bảo là biến được khai báo là register sẽ được đặt trong mô ̣t thanh ghi hoă ̣c thâ ̣m chí tố c đô ̣ truy câ ̣p sẽ nhanh hơn . Đó chỉ là mô ̣t gơ ̣i ý cho trình biên dịch. Không thể thực hiê ̣n các biế n thanh ghi kiể u này , chúng cũng chỉ có thể là các biến điạ phương, không thể là các biế n toàn cu ̣c hoă ̣c các biế n tinh và nói chung chúng ta ̃ nên tránh dùng chúng. Biế n tinh (static variable) ̃ Các biến tĩnh được khai báo bằng từ khóa static . Bình thườ ng đố i với mô ̣t biế n đươ ̣c khai báo cu ̣c bô ̣ trong mô ̣t hàm số , nó sẽ tự động bị loại bỏ khỏi bộ nhớ khi hàm đươ ̣c go ̣i thực hiê ̣n xong . Khi hàm đươ ̣c go ̣i thực hiê ̣n la ̣i lầ n nữa , các biến cục bộ lại đươ ̣c khởi ta ̣o la ̣i và c ứ thế. Tuy nhiên đôi khi chúng ta muố n lưu la ̣i các giá tri ̣của mô ̣t biế n số đã có đươ ̣c trong các lầ n go ̣i thực hiê ̣n trước của hàm , khi đó viê ̣c dùng 16
- biế n static là hơ ̣p lý . Các biến static chỉ được khởi tạo lần đầu tiên kh i hàm đươ ̣c go ̣i tới lầ n đầ u tiên . Chúng ta có thể băn khoăn tự hỏi là vậy tại sao không dùng các biến toàn cục câu trả lời là các biến static có tầm hoạt động trong một thân hàm do đó chúng ta có thể thu hẹp các lỗi liên quan tới viê ̣c sử du ̣ng biế n này , có nghĩa khả năng lỗi là thấ p hơn so với dùng biế n toàn cu ̣c. Ngoài ý nghĩa trên từ khóa static thường có một ý nghĩa khác đó là “không thể sử dụng ngoài một phạm vi nhất định” . Khi từ khóa static được dùng để khai báo một tên hàm hoặc một biến nằm ngoài tất cả các hàm trong một file mã nguồn thì có nghĩa là biế n đó chỉ có tầ m hoa ̣t đô ̣ng trong file đó mà thôi . Khi đó chúng ta nói là biế n đó có tầ m hoạt động file. 2.5 Liên kế t biế n khi biên dich ̣ Để hiể u cách thức hoa ̣t đô ̣ng của các chương trinh C và C ++ chúng ta cần phải hiểu ̀ quá trình liên kết diễn ra như thế nào . Có hình thức liên kết các biến khi biên dịch : liên kế t trong và liên kế t ngoài . Liên kế t trong có nghia là bô ̣ nhớ (vùng lưu trữ) đươ ̣c ta ̣o ra để biể u diễn đinh danh ̃ ̣ chỉ cho file đang được biên dịch . Các file khác có thể sử dụng định danh đó đối với liên kế t trong , hoă ̣c với mô ̣t biế n toàn cu ̣c . Liên kế t trong thường đươ ̣c thực hiê ̣n với các biến static. Liên kế t ngoài có nghia là mỗi vùng nhớ đươ ̣c ta ̣o ra để biể u diễn đinh danh cho tấ t ̃ ̣ cả các file đang được biên dịch. Các vùng nhớ này chỉ được tạo ra mô ̣t lầ n và trinh liên ̀ kế t phải sắ p xế p la ̣i tấ t cả các tham chiế u tới vùng nhớ đó . Các tên hàm và các biến toàn cục có các liên kết ngoài và chúng có thể được truy cập trong các file khác bằng cách khai báo bằng từ k hóa extern. Các biến định nghĩa ngoài các hàm (trừ các const ) và các định nghĩa hàm là mặc định đối với liên kết ngoài . Chúng ta có thể buộc chúng thực hiê ̣n các liên kế t trong bằ ng từ khóa static và chỉ rõ liên kế t ngo ài bằng từ khóa extern. Các biến cục bộ chỉ được sử dụng tạm thời , trên stack khi các hàm đươ ̣c go ̣i tới . Trình liên kết không biết tới chúng và do đó không có quá trình liên kết nào được thực hiê ̣n. 2.6 Các hằng Trong các trình biên dịch C cổ điển chúng ta có thể khai báo các hằng bằng cách sử dụng chỉ thị tiền xử lý, ví dụ: #define PI 3.14159 Khi đó trong quá trinh tiề n xử lý bô ̣ tiề n xử lý sẽ thực hiê ̣n thay thế tấ t cả các ký ̀ hiê ̣u PI mà nó gặp trong các file mã nguồn bằng giá trị 3.14159. Chúng ta vẫn có thể sử dụng cách này trong C ++ tuy nhiên có rấ t nhiề u vấ n đề đố i với kiể u khai báo này . Chúng ta không thể thực hiện kiểm tra kiểu đối với PI , không thể lấy địa chỉ của PI (vì thế không thể dùng con trỏ trỏ vào biến này ). PI cũng không thể là mô ̣t biế n có kiể u người dùng đinh nghia . Cũng không thể xác định được tầm ̣ ̃ hoạt động của PI. C++ sử du ̣ng từ khóa const để khai báo các hằng, cú pháp khai báo giống như khai báo biến chỉ khác là giá trị của hằng là không thay đổi . Các hằng trong C ++ đều phải khởi tạo trước khi sử dụng . Các giá trị hằng cho các kiể u built-in đươ ̣c biể u diễn như là các số thập phân, bát phân, số hexa hoă ̣c các số dấ u phẩ y đô ̣ng (đá ng buồ n là các số nhi ̣phân đươ ̣c cho là không quan tro ̣ng ) hoă ̣c là các ký tự. 17
CÓ THỂ BẠN MUỐN DOWNLOAD
-
Bài giảng Lập trình hướng đối tượng: Chương 3 - Nguyễn Sơn Hoàng Quốc, ThS. Nguyễn Tấn Trần Minh Khang
38 p | 139 | 19
-
Bài giảng Lập trình hướng đối tượng - Chương 2: Đối tượng và lớp
21 p | 171 | 15
-
Bài giảng Lập trình hướng đối tượng: Chương 2 - Nguyễn Sơn Hoàng Quốc, ThS. Nguyễn Tấn Trần Minh Khang
14 p | 174 | 12
-
Bài giảng Lập trình hướng đối tượng - Chương 3: Kế thừa
18 p | 134 | 10
-
Bài giảng Lập trình hướng đối tượng - Chương 1: Phương pháp lập trình hướng đối tượng
9 p | 140 | 9
-
Bài giảng Lập trình hướng đối tượng (dùng Java): Chương 1 - Trần Minh Thái (2017)
55 p | 80 | 8
-
Bài giảng Lập trình hướng đối tượng - Bài 1: Tổng quan lập trình hướng đối tượng
53 p | 119 | 8
-
Bài giảng Lập trình hướng đối tượng: Chương 1 - Trần Thị Anh Thi
7 p | 197 | 7
-
Bài giảng Lập trình hướng đối tượng - Bài 1: Tổng quan về OOP
0 p | 145 | 7
-
Bài giảng Lập trình hướng đối tượng 1: Chương 1 - ThS. Thái Kim Phụng
39 p | 100 | 6
-
Bài giảng Lập trình hướng đối tượng (dùng JAVA): Chương 1 - Trần Minh Thái
40 p | 99 | 5
-
Bài giảng Lập trình hướng đối tượng: Chương 1 - GV. Hà Văn Sang
29 p | 89 | 5
-
Bài giảng Lập trình hướng đối tượng – Bài 01: Tổng quan về OOP
47 p | 63 | 5
-
Bài giảng Lập trình hướng đối tượng: Bài 1 - Tổng quan về lập trình hướng đối tượng
47 p | 11 | 4
-
Bài giảng Lập trình hướng đối tượng và C++: Chương 1
15 p | 103 | 4
-
Bài giảng Lập trình hướng đối tượng và C++: Chương 0
2 p | 83 | 4
-
Bài giảng Lập trình hướng đối tượng: Chương 1 - Các khái niệm cơ bản trong lập trình hướng đối tượng
36 p | 15 | 3
-
Bài giảng Lập trình hướng đối tượng (Object-Oriented Programming) - Chương 2: Phương pháp lập trình hướng đối tượng
35 p | 8 | 3
Chịu trách nhiệm nội dung:
Nguyễn Công Hà - Giám đốc Công ty TNHH TÀI LIỆU TRỰC TUYẾN VI NA
LIÊN HỆ
Địa chỉ: P402, 54A Nơ Trang Long, Phường 14, Q.Bình Thạnh, TP.HCM
Hotline: 093 303 0098
Email: support@tailieu.vn