lập trình c++,nguyễn mạnh hùng,hvcnbcvt BÀI GIẢNG NGÔN NGỮ LẬP TRÌNH C++ Biên soạn TS Nguyễn Mạnh Hùng Hiệu chỉnh Th S Nguyễn Mạnh Sơn CuuDuongThanCong com https //fb com/tailieudientucntt cu u d uo n[.]
LẬP TRÌNH TUYẾN TÍNH
Lập trình tuyến tính đặc trưng bởi tư duy tuần tự, trong đó chương trình được thực hiện từ đầu đến cuối, với mỗi lệnh được thực hiện liên tiếp cho đến khi hoàn tất.
Lập trình tuyến tính có hai đặc trưng:
Đơn giản: chương trình được tiến hành đơn giản theo lối tuần tự, không phức tạp
Đơn luồng: chỉ có một luồng công việc duy nhất, và các công việc được thực hiện tuần tự trong luồng đó
Lập trình tuyến tính có nhiều ưu điểm nhờ vào tính đơn giản của nó, giúp chương trình trở nên dễ hiểu và dễ thực hiện Phương pháp này thường được ứng dụng trong các chương trình đơn giản, mang lại hiệu quả cao trong việc giải quyết các bài toán cơ bản.
Nhược điểm: Với các ứng dụng phức tạp, người ta không thể dùng lập trình tuyến tính để giải quyết
Ngày nay, lập trình tuyến tính chủ yếu xuất hiện trong các modul nhỏ của các phương pháp lập trình khác Chẳng hạn, trong một chương trình con của lập trình cấu trúc, các lệnh được thực hiện theo thứ tự từ đầu đến cuối.
LẬP TRÌNH HƯỚNG CẤU TRÚC
1.2.1 Đặc trưng của lập trình hướng cấu trúc
Trong lập trình hướng cấu trúc, chương trình chính được phân chia thành các chương trình con, mỗi chương trình con đảm nhận một nhiệm vụ cụ thể Chương trình chính sẽ gọi các chương trình con dựa trên một thuật toán hoặc cấu trúc đã được xác định trước.
Các ngôn ngữ lập trình cấu trúc phổ biến bao gồm Pascal, C và C++ Trong đó, C++ không chỉ kế thừa các đặc trưng của lập trình cấu trúc từ C mà còn tích hợp các tính năng của lập trình hướng đối tượng, do đó được gọi là ngôn ngữ lập trình nửa cấu trúc, nửa hướng đối tượng Đặc trưng cơ bản nhất của lập trình cấu trúc thể hiện qua mối quan hệ giữa các thành phần trong chương trình.
Chương trình = Cấu trúc dữ liệu + Giải thuật
Cấu trúc dữ liệu là cách tổ chức dữ liệu, cách mô tả bài toán dưới dạng ngôn ngữ lập trình
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
Mỗi chương trình con có thể được gọi thực hiện nhiều lần trong một chương trình chính
Các chương trình con có thể được gọi theo bất kỳ thứ tự nào, tùy thuộc vào thuật toán trong chương trình chính mà không bị ràng buộc bởi thứ tự khai báo của chúng.
Các ngôn ngữ lập trình cấu trúc cung cấp một số cấu trúc lệnh điều khiển chương trình Ưu điểm
Chương trình sáng sủa, dễ hiểu, dễ theo dõi
Tư duy giải thuật rõ ràng
Lập trình cấu trúc không cho phép tái sử dụng mã nguồn, vì các thuật toán phụ thuộc vào cấu trúc dữ liệu Khi có sự thay đổi trong cấu trúc dữ liệu, điều này dẫn đến việc phải điều chỉnh thuật toán, tức là phải viết lại toàn bộ chương trình.
Lập trình cấu trúc không hiệu quả cho các dự án phần mềm lớn, vì tư duy này chỉ phù hợp với các bài toán nhỏ trong một module Nó không thể giải quyết mối quan hệ vĩ mô giữa các module của phần mềm, dẫn đến hạn chế trong việc phát triển và quản lý hệ thống phức tạp.
Vấn đề cốt lõi trong lập trình cấu trúc là xác định cách phân chia chương trình chính thành các chương trình con, sao cho phù hợp với yêu cầu, chức năng và mục đích của từng bài toán cụ thể.
Thông thường, để phân rã bài toán trong lập trình cấu trúc, người ta sử dụng phương pháp thiết kế trên xuống (top-down) cuu duong than cong com
1.2.2 Phương pháp thiết kế trên xuống (top-down)
Phương pháp thiết kế top-down là cách tiếp cận bài toán từ tổng quan đến chi tiết, chia nhỏ bài toán thành các bài toán con Mỗi bài toán con có thể tiếp tục được phân chia thành những bài toán nhỏ hơn, giúp dễ dàng quản lý và giải quyết vấn đề một cách hiệu quả.
Quá trình làm mịn dần, hay còn gọi là quá trình phân chia, sẽ kết thúc khi các bài toán con không cần phải chia nhỏ thêm Điều này có nghĩa là mỗi bài toán con có thể được giải quyết bằng một chương trình con sử dụng một giải thuật đơn giản.
Phương pháp top-down có thể được áp dụng để giải quyết bài toán xây dựng một căn nhà mới bằng cách phân rã bài toán thành các bước cụ thể.
Ở mức thứ nhất, chia bài toán xây nhà thành các bài toán nhỏ hơn như: làm móng, đổ cột, đổ trần, xây tường, lợp mái
Ở mức thứ hai, các công việc liên quan đến xây dựng móng nhà được phân rã thành nhiều nhiệm vụ cụ thể hơn Các công việc này bao gồm đào móng, gia cố nền, làm khung sắt và đổ bê tông Đặc biệt, công việc đổ cột cũng cần được phân rã thành các bước chi tiết để đảm bảo chất lượng công trình.
Ở mức thứ ba, công việc đào móng được phân chia thành các nhiệm vụ cụ thể như: đo đạc, cắm mốc, chăng dây, đào và kiểm tra móng Đồng thời, việc gia cố nền cũng cần được phân rã thành các công việc chi tiết để đảm bảo hiệu quả thi công.
Quá trình phân rã có thể dừng lại tại đây, vì các công việc như đo đạc, cắm mốc, chăng dây và đào có thể được thực hiện ngay mà không cần phải chia nhỏ thêm.
Phương pháp top-down có thể dẫn đến nhiều kết quả khác nhau khi giải quyết cùng một bài toán, do sự khác biệt trong tiêu chí phân rã bài toán thành các bài toán con.
Áp dụng phương pháp top-down trong việc xây dựng nhà có thể mang lại hiệu quả, nhưng nếu thay đổi cách phân chia bài toán, kết quả đạt được có thể khác biệt đáng kể so với phương pháp ban đầu.
Ở mức thứ nhất, chia bài toán xây nhà thành các bài toán nhỏ hơn như: làm phần gỗ, làm phần sắt, làm phần bê tông và làm phần gạch
Ở mức thứ hai, công việc trong ngành gỗ có thể được phân chia thành các nhiệm vụ cụ thể như xẻ gỗ, gia công gỗ, tạo khung và lắp đặt vào nhà Tương tự, ngành sắt cũng có thể được chia nhỏ thành các công việc chuyên biệt.
Rõ ràng, với cách làm mịn thế này, ta sẽ thu được một kết quả khác hẳn với cách thức đã thực hiện ở phần trên.
LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
1.3.1 Lập trình hướng đối tượng
Trong lập trình hướng đối tượng: cuu duong than cong com
Người ta coi các thực thể trong chương trình là các đối tượng và sau đó, người ta trừu tượng hoá đối tượng thành lớp đối tượng
Dữ liệu được cấu trúc thành các thuộc tính của lớp, giúp ngăn chặn việc thay đổi dữ liệu một cách tùy tiện trong chương trình Việc hạn chế truy cập dữ liệu chỉ cho phép thông qua đối tượng và các phương thức mà đối tượng cung cấp, đảm bảo tính bảo mật và toàn vẹn của dữ liệu.
Trong lập trình hướng đối tượng, quan hệ giữa các lớp có thể là quan hệ ngang hàng hoặc quan hệ kế thừa Khi lớp B kế thừa từ lớp A, lớp A được gọi là lớp cơ sở, trong khi lớp B được gọi là lớp dẫn xuất.
Ngôn ngữ lập trình hướng đối tượng phổ biến hiện nay bao gồm Java và C++ Mặc dù C++ sở hữu nhiều đặc trưng của lập trình hướng đối tượng, nhưng nó không phải là ngôn ngữ thuần túy hướng đối tượng.
Lập trình hướng đối tượng có hai đặc trưng cơ bản:
Dữ liệu được đóng gói thành các thuộc tính của lớp đối tượng, và việc truy cập vào dữ liệu này chỉ có thể thực hiện thông qua các phương thức của lớp đối tượng.
Sử dụng lại mã nguồn thông qua cơ chế kế thừa cho phép các lớp đối tượng kế thừa từ các lớp khác, giúp tái sử dụng các phương thức mà không cần định nghĩa lại Ưu điểm của phương pháp này là tiết kiệm thời gian và công sức trong việc phát triển phần mềm.
Lập trình hướng đối tượng có một số ưu điểm nổi bật:
Dữ liệu không còn bị thay đổi tự do trong chương trình, vì đã được đóng gói vào các đối tượng Để truy cập dữ liệu, người dùng phải sử dụng các phương thức được phép của đối tượng.
Khi thay đổi cấu trúc dữ liệu của một đối tượng, chỉ cần điều chỉnh một số thành phần của đối tượng dẫn xuất mà không cần sửa đổi mã nguồn của các đối tượng khác Điều này giúp hạn chế tác động tiêu cực từ việc thay đổi dữ liệu đến các đối tượng khác trong chương trình.
Việc tái sử dụng mã nguồn giúp tiết kiệm tài nguyên và thời gian, nhờ vào nguyên tắc kế thừa cho phép các lớp dẫn xuất sử dụng trực tiếp các phương thức từ lớp cơ sở mà không cần định nghĩa lại.
Phù hợp với các dự án phần mềm lớn, phức tạp
1.3.2 Một số khái niệm cơ bản
Trong mục này, chúng ta sẽ làm quen với một số khái niệm cơ bản trong lập trình hướng đối tượng Bao gồm:
Khái niệm đối tượng (object) cuu duong than cong com
Khái niệm đóng gói dữ liệu (encapsulation)
Khái niệm kế thừa (inheritance)
Khái niệm đa hình (polymorphism) Đối tượng (Object)
Trong lập trình hướng đối tượng, đối tượng là đơn vị cơ bản nhất, bao gồm dữ liệu và phương thức Dữ liệu và cách xử lý chỉ là thành phần của đối tượng, không phải là thực thể độc lập Mỗi đối tượng chứa dữ liệu riêng và có các phương thức để thao tác trên dữ liệu đó, thể hiện mối quan hệ giữa dữ liệu và hành động trong lập trình.
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 Đó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
Để truy cập dữ liệu, người dùng cần thông qua các đối tượng và sử dụng các phương thức mà đối tượng đó cung cấp.
C++ là ngôn ngữ lập trình nửa đối tượng, cho phép người dùng định nghĩa các biến dữ liệu và hàm tự do, điều này xuất phát từ sự kế thừa của ngôn ngữ C, một ngôn ngữ lập trình thuần cấu trúc.
Tính kế thừa trong lập trình hướng đối tượng cho phép một lớp kế thừa từ nhiều lớp đã tồn tại, giúp lớp mới sử dụng dữ liệu và phương thức của các lớp cơ sở như của chính mình Lớp dẫn xuất còn có thể bổ sung thêm dữ liệu và phương thức mới Ưu điểm của kế thừa là khi thay đổi dữ liệu trong lớp cơ sở, các lớp dẫn xuất không cần phải thay đổi Đa hình, khái niệm song hành với kế thừa, cho phép lớp dẫn xuất sử dụng lại các phương thức của lớp khác, đồng thời có khả năng định nghĩa lại một số phương thức của lớp cơ sở, thể hiện sự nạp chồng phương thức trong kế thừa.
Nhờ tính đa hình, chúng 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 đến lớp của đối tượng đó Chương trình sẽ tự động xác định xem đối tượng thuộc lớp cơ sở hay lớp dẫn xuất và gọi phương thức tương ứng.
1.3.3 Lập trình hướng đối tượng trong C++
C++ là một ngôn ngữ lập trình được phát triển từ ngôn ngữ lập trình C, do đó nó mang tính chất kết hợp giữa lập trình hướng đối tượng và lập trình cấu trúc.
Những đặc trưng hướng đối tượng của C++
Cho phép định nghĩa lớp đối tượng
Đóng gói dữ liệu vào các lớp đối tượng cho phép định nghĩa phạm vi truy cập dữ liệu thông qua các từ khóa như public, protected và private.
Cho phép kế thừa lớp với các kiểu kế thừa khác nhau tuỳ vào từ khoá dẫn xuất
Cho phép lớp dẫn xuất sử dụng các phương thức của lớp cơ sở (trong phạm vi quy định)
Cho phép định nghĩa chồng phương thức trong lớp dẫn xuất
Những hạn chế hướng đối tượng của C++
Những hạn chế này là do C++ được phát triển từ một ngôn ngữ lập trình thuần cấu trúc C
Cho phép định nghĩa và sử dụng các biến dữ liệu tự do
Cho phép định nghĩa và sử dụng các hàm tự do
KHÁI NIỆM CON TRỎ
Con trỏ là một biến đặc biệt dùng để lưu trữ địa chỉ của một biến khác, và kiểu của con trỏ tương ứng với kiểu của biến mà nó trỏ tới Để khai báo một con trỏ, cú pháp sẽ được sử dụng như sau:
*;
Kiểu dữ liệu trong C++ bao gồm các kiểu dữ liệu cơ bản, kiểu dữ liệu có cấu trúc và kiểu đối tượng do người dùng tự định nghĩa.
Tên con trỏ: Tuân theo qui tắc đặt tên biến của C++:
- Chỉ được bắt đầu bằng một kí tự (chữ), hoặc dấu gạch dưới “_”
- Bắt đầu từ kí tự thứ hai, có thể có kiểu kí tự số
- Không có dấu trống (space bar) trong tên biến
- Có phân biệt chữ hoa và chữ thường
- Không giới hạn độ dài tên biến
Ví dụ, để khai báo một biến con trỏ có kiểu là int và tên là pointerInt, ta viết như sau: int *pointerInt;
Có thể viết dấu con trỏ “*” ngay sau kiểu dữ liệu, nghĩa là hai cách khai báo sau là tương đương: int *pointerInt; int* pointerInt;
Các cách khai báo con trỏ như sau là sai cú pháp:
*int pointerInt; // Khai báo sai con trỏ cuu duong than cong com int pointerInt*; // Khai báo sai con trỏ
Con trỏ được sử dụng theo hai phép toán:
Lấy địa chỉ con trỏ để thao tác
Lấy giá trị của con trỏ để thao tác
Lấy địa chỉ con trỏ
Bản thân con trỏ sẽ được gán cho địa chỉ của một biến có cùng kiểu dữ liệu với nó Cú pháp của phép gán như sau:
= &;
Trong phép lấy địa chỉ, tên con trỏ không có dấu “*”
Ví dụ, khi khai báo int x, *px; và gán px = &x, con trỏ px sẽ có kiểu int và trỏ đến địa chỉ của biến x, cũng là kiểu nguyên Phép toán & sẽ trả về địa chỉ của biến tương ứng.
Lấy giá trị của con trỏ
Phép lấy giá trị của con trỏ được thực hiện bằng cách gọi tên:
Trong phép lấy giá trị, phải có dấu con trỏ “*” Nếu không có dấu con trỏ, sẽ trở thành phép lấy địa chỉ con trỏ
Ví dụ: int x = 12, y, *px; px = &y;
*px = x; con trỏ px vẫn trỏ tới địa chỉ biến y và giá trị của biến y sẽ là 12
Phép gán giữa các con trỏ
Các con trỏ cùng kiểu có thể gán cho nhau thông qua phép gán và lấy địa chỉ con trỏ:
= ;
Lưu ý cuu duong than cong com
Trong phép gán giữa các con trỏ, cần sử dụng phép lấy địa chỉ của con trỏ mà không bao gồm dấu “*” trong tên con trỏ, và không được phép sử dụng phép lấy giá trị của con trỏ.
Hai con trỏ cần phải có cùng kiểu Nếu hai con trỏ có kiểu khác nhau, cần sử dụng các phương thức ép kiểu tương tự như khi gán các biến thông thường có kiểu khác nhau.
Trong ví dụ này, biến x được gán giá trị 12, và hai con trỏ px và py được sử dụng để trỏ đến địa chỉ của x Khi px trỏ đến x, py cũng trỏ vào cùng địa chỉ đó, nên giá trị mà *py tham chiếu cũng là 12, giống như giá trị của x.
*px và giá trị biến x
Chương trình 2.1 minh hoạ việc dùng con trỏ giữa các biến của một chương trình C++
#include void main(void){ int x = 12, *px, *py; cout