Giáo trình Lập trình hướng đối tượng - Lập trình máy tính

Lập trình cấu trúc.

Tư tưởng chính của lập trình cấu trúc là tổ chức chương trình thành các chương

trình con. Mỗi chương trình con đảm nhận xử lý một công việc nhỏ trong toàn bộ hệ thống. Mỗi chương trình con này lại có thể chia nhỏ thành các chương trình con nhỏ hơn. Quá trình phân chia như vậy tiếp tục diễn ra cho đến các chương trình con nhỏ nhận được đủ đơn giản, đó là quá trình làm mịn dần. Các chương trình con tương đối độc lập với nhau. Ngôn ngữ lập trình thể hiện rõ nét nhất phương pháp lập trình cấu trúc là ngôn ngữ lập trình Pascal. Trong ngôn ngữ lập trình C chỉ có một loại chương trình con là hàm.

Hàm là một đơn vị chương trình độc lập dùng để thực hiện một phần việc nào đó như: nhập số liệu, in kết quả hay thực hiện một số tính toán. Hàm cần có đối và các biến, mảng cục bộ dùng riêng cho hàm.

Việc trao đổi dữ liệu giữa các hàm thực hiện thông qua các đối và các biến toàn bộ Các ngôn ngữ như C, PASCAL, FOXPRO là các ngôn ngữ cho phép triển khai.

phương pháp lập trình cấu trúc.

Một chương trình cấu trúc gồm các cấu trúc dữ liệu (như biến, mảng, bản ghi) và các hàm, thủ tục.

Nhiệm vụ chính của việc tổ chức thiết kế chương trình hướng cấu trúc là tổ chức chương trình thành các hàm, thủ tục: Chương trình sẽ bao gồm các hàm, thủ tục nào.

Ví dụ : Xét yêu cầu sau: Viết chương trình nhập toạ độ (x,y) của một dãy điểm, sau đó tìm một cặp điểm cách xa nhau nhất.

Trên tư tưởng của lập trình hướng cấu trúc có thể tổ chức chương trình như sau:

+ Sử dụng 2 mảng thực toàn bộ x và y để chứa toạ độ dãy điểm

+ Xây dựng 2 hàm:

Hàm nhapsl dùng để nhập toạ độ n điểm, hàm này có một đối là biến nguyên n và được khai báo như sau:

void nhapsl(int n);

Hàm do_dai dùng để tính độ dài đoạn thẳng đi qua 2 điểm có chỉ số là i và j,

nó được khai báo như sau:

float do_dai(int i, int j);

Chương trình C cho bài toán trên được viết như sau:

#include

#include

#include float x[100],y[100]; float do_dai(int i, int j)

{

return sqrt(pow(x[i]-x[j],2)+pow(y[i]-y[j],2));

}

void nhapsl(int n)

{

int i;

for (i=1;i<>

{

printf("\nNhap toa do x, y cua diem thu %d : ",i);

scanf("%f%f",&x[i],&y[i]);

}

}

void main()

{

int n,i,j,imax,jmax; float d,dmax; printf("\nSo diem N= "); scanf("%d",&n); nhapsl(n);

dmax=do_dai(1,2); imax=1;jmax=2;

for (i=1;i<>

for (j=i+1;j<>

{

d=do_dai(i,j);

if (d>dmax)

{

dmax=d; imax=i; jmax=j;

}

}

printf("\nDoan thang lon nhat co do dai bang: %0.2f",dmax); printf("\n Di qua 2 diem co chi so la %d va %d",imax,jmax); getch();

}

Tuy nhiên khi sử dụng phương pháp lập trình cấu trúc thì Chương trình=Cấu trúc dữ liệu+Giải thuật. Điều này đòi hỏi người lập trình phải có kiến thức vững về cấu trúc dữ liệu. Khó khăn gặp phải trong lập trình cấu trúc là giải thuật của chương trình phụ thuộc rất chặt chẽ vào cấu trúc dữ liệu, do đó chỉ cần có một thay đổi nhỏ ở cấu trúc dữ liệu cũng có thể làm thay đổi giải thuật và như vậy phải viết lại chương trình. Điều này không thể thích hợp khi phải xây dựng một dự án phần mềm lớn. Phương pháp lập trình hướng đối tượng ra đời khắc phục được nhược điểm này của lập trình cấu trúc.

 

doc 171 trang duykhanh 8141
Bạn đang xem tài liệu "Giáo trình Lập trình hướng đối tượng - Lập trình máy tính", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Giáo trình Lập trình hướng đối tượng - Lập trình máy tính

Giáo trình Lập trình hướng đối tượng - Lập trình máy tính
 Hienthi();
Định nghĩa các hàm thành phần của khuôn hình lớp, phân biệt hai trường hợp:
- Khi hàm thành phần được định nghĩa bên trong định nghĩa lớp thì không có gì thay đổi.
- Khi hàm thành phần được định nghĩa bên ngoài lớp, khi đó cần phải nhắc lại
cho chương trình biết các tham số kiểu của khuôn hình lớp. Ví dụ: phải nhắc lại template trước định nghĩa hàm
Ví dụ: hàm Hienthi() được định nghĩa ngoài lớp:
template void SO::Hienthi()
{
cout <<giatri;
}
Giống như khuôn hình hàm, các khuôn hình lớp có thể có các tham số kiểu và
tham số biểu thức.
Ví dụ một lớp mà các thành phần có các kiểu dữ liệu khác nhau được khai báo
theo dạng:
template 
class {
T x; U y;
.....
Z fct1 (int);
.....
};
Một lớp thể hiện được khai báo bằng cách liệt kê đằng sau tên khuôn hình lớp các tham số thực, là tên kiểu dữ liệu, với số lượng bằng các tham số trong danh sách của khuôn hình lớp (template)
7.2.3 Sử dụng khuôn hình lớp.
Sau khi một khuôn hình lớp đã được định nghĩa, nó sẽ được dùng để khai báo
các đối tượng theo dạng sau :
Tên_lớp Tên_đối_tượng;
Ví dụ :
câu lệnh khai báo SO so1;
sẽ khai báo một đối tượng so1 có thành phần dữ liệu giatri có kiểu nguyên int. SO có vai trò như một kiểu dữ liệu lớp; người ta gọi nó là một lớp thể
hiện của khuôn hình lớp SO.
Một cách tổng quát, khi áp dụng một kiểu dữ liệu nào đó với khuôn hình lớp SO
ta sẽ có được một lớp thể hiện tương ứng với kiểu dữ liệu.
Tương tự với các khai báo SO so2; cho phép khai báo một đối tượng
so2 mà thành phần dữ liệu giatri có kiểu float.
Ví dụ:
#include 
#include 
template class SO
{
kieuso giatri;
public :
SO (kieuso x =0);
void Hienthi(){
cout<<"Gia tri cua so :"<<giatri<<endl;
}
};
void main(){
clrscr();
SO soint(10); soint.Hienthi(); SO sofl(25.4); sofl.Hienthi();
getch();
}
Kết quả trên màn hình là:
Gia tri cua so : 10
Gia tri cua so : 25.4
BÀI TẬP CHƯƠNG 7
1. Viết chương trình thực hiện các yêu cầu:
- Xây dựng khuôn hình hàm Hoandoi cho phép hoán đổi giá trị hai biến số truyền vào
- Sử dụng khuôn hình hàm Hoandoi để xây dựng khuôn hình hàm Sort sắp xếp giá trị của một mảng
- Xây dựng khuôn hình hàm In để in ra giá trị của một mảng ra màn hình
- Sử dụng các khuôn hình hàm đã xây dựng để viết một chương trình sắp xếp giá trị của 2 mảng, một mảng nguyên và một mảng thực
- Xây dựng lớp phân số
- Sử dụng các khuôn hình hàm đã xây dựng để viết một chương trình sắp xếp giá trị của một mảng gồm các phân số
2. Xây dựng khuôn hình hàm thực hiện:
a. Xây dựng khuôn hàm hoán đổi cho phép đổi giá trị của hai biến số truyền vào.
b. Xây dựng khuôn hình hàm sắp xếp có sử dụng khuôn hình hàm hoán đổi để sắp xếp giá trị của một mảng theo chiều tăng dần.
c. Xây dựng khuôn hình hàm tìm số lớn nhất trong một một mảng
d. Xây dựng khuôn hình hàm để in giá trị của một mảng ra màn hình. e. Viết hàm main sử dụng các khuôn hình hàm đã xây dựng :
- Sắp xếp giá trị của hai mảng, một mảng các phần tử có kiểu nguyên và một mảng các
phần tử có kiểu thực.
- Hiển thị số lớn nhất trong mảng các phần tử có kiểu thực.
3. Xây dựng khuôn hình hàm thực hiện:
a. Xây dựng khuôn hình hàm tìm số lớn nhất trong một mảng
b. Xây dựng khuôn hình hàm để in giá trị của một mảng ra màn hình. c. Viết hàm main sử dụng các khuôn hình hàm đã xây dựng :
- Hiển thị mảng đã nhập vào ra màn hình.
- Hiển thị số lớn nhất trong hai mảng : một mảng gồm các số nguyên và một mảng gồm các số thực.
4. Xây dựng lớp phân số (một phân số phải được tối giản) để xây dựng các chồng toán
tử sau:
a. Xây dựng chồng toán tử cộng, nhân hai phân số
b. Xây dựng chồng toán tử nhập và hiển thị phân số. c. Viết hàm main các toán tử đã xây dựng :
- Nhập vào hai phân số.
- Hiển thị tổng và tích của hai phân số đó.
5. Xây dựng khuôn hình hàm thực hiện:
a. Xây dựng khuôn hình hàm tìm số nhỏ thứ hai trong một mảng.
b. Xây dựng khuôn hình hàm để in giá trị của một mảng ra màn hình theo thứ tự sắp xếp tăng dần.
c. Viết hàm main sử dụng các khuôn hình hàm đã xây dựng :
- Nhập vào hai mảng: một mảng gồm các số nguyên và một mảng gồm các số thực
- Hiển thị mảng đã nhập vào ra màn hình.
- Hiển thị số nhỏ thứ hai của hai mảng đã nhập.
6. Xây dựng khuôn hình hàm thực hiện:
a. Xây dựng khuôn hình hàm tìm số âm nhỏ nhất trong một mảng.
b. Xây dựng khuôn hình hàm để hiển thị tổng các số dương của một mảng ra màn hình.
c. Viết hàm main sử dụng các khuôn hình hàm đã xây dựng :
- Nhập vào hai mảng: một mảng gồm các số nguyên và một mảng gồm các số thực
- Hiển thị số âm nhỏ nhất của hai mảng đã nhập ra màn hình.
- Hiển thị tổng các số dương của hai mảng đã nhập.
7. Viết chương trình khai báo khuôn hình lớp để mô phỏng hoạt động của hàng đợi hoặc ngăn xếp trên các kiểu đối tượng khác nhau
Phụ lục 1
Thứ tự ưu tiên của các phép toán
Các phép toán được chia thành 16 nhóm. Các phép toán trong cùng nhóm có mực độ ưu tiên như nhau.
Về trình tự kết hợp thì:
+ Các phép tính của nhóm 2, nhóm 14 và toán tử gán (nhóm 15) kết hợp từ phải sang trái.
+ Các phép toán còn lại kết hợp từ trái qua phải.
1. Nhóm một
() Gọi hoàm (Function call)
[] Chỉ số mảng (Array subscript)
-> Chọn gián tiếp một thành phần (indirect component selector)
:: Xác định phạm vi truy nhập (scope access/resolution)
. Chọn trực tiếp một thành phần (direct component selector)
2. Nhóm hai
() Gọi hoàm (Function call)
! Phủ định logic (Logical negation -NOT)
~ Lấy phần bù theo bit (Bitwise (1's) complement)
+ Dấu cộng (Unary plus)
- Dấu trừ (Unary minus)
++ Phép tăng một (Preincrement or postincrement)
-- Phép giảm một (Predecrement or postdecrement)
& Phép lấy địa chỉ (Address)
* Truy nhập gián tiếp (Indirection)
sizeof Cho kích thước của toán hạng (returns size of operand, in bytes)
new Cấp phát bộ nhớ động (dynamically allocates C++ storage)
delete Giải phóng bộ nhớ (dynamically deallocates C++ storage)
3. Nhóm ba
* Nhân ( Multiply)
/ Chia (Divide)
% Lấy phần dư (Remainder - modulus)
4. Nhóm bốn
.* Gọi gián tiếp tới thành phần từ một biến đối tượng
->* Gọi gián tiếp tới thành phần từ một con trỏ đối tượng
5. Nhóm năm
+ Cộng (Binary plus)
- Trừ (Binary minus)
6. Nhóm sáu
<< Dịch trái (Shift left)
>> Dịch phải (Shift right)
7. Nhóm bẩy
< Nhỏ hơn (Less than)
<= Nhỏ hơn hoặc bằng (Less than or equal to)
> Lớn hơn (Greater than)
>= Lớn hơn hoặc bằng (Greater than or equal to)
8. Nhóm tám
== Bằng (Equal to)
!= Không bằng (Not equal to)
9. Nhóm chín
& Phép và theo bit (Bitwise AND)
10. Nhóm mười
^ Phép hoặc loại trừ theo bit (Bitwise XOR)
11. Nhóm mười một
| Phép hoặc theo bit (Bitwise OR)
12. Nhóm mười hai
&& Phép và logic (Logical AND)
13. Nhóm mười ba
&& Phép hoặc logic (Logical OR)
14. Nhóm mười bốn
?: Toán tử điều kiện (a ? x : y means "if a then x, else y")
15. Nhóm mười năm
= Phép gán đơn giản (Simple assignment)
*= Phép gán sau khi nhân (Assign product)
/= Phép gán sau khi chia (Assign quotient)
%= Phép gán sau khi lấy phần dư (Assign remainder)
+= Phép gán sau khi cộng (Assign sum)
-= Phép gán sau khi trừ (Assign difference)
&= Phép gán sau khi AND theo bit (Assign bitwise AND)
^= Phép gán sau khi XOR theo bit (Assign bitwise XOR)
|= Phép gán sau khi OR theo bit (Assign bitwise OR)
<<= Phép gán sau khi dịch trái (Assign left shift)
>>= Phép gán sau khi dịch phải (Assign right shift)
16. Nhóm mười sáu
, Toán tử phẩy dùng để phân cách các phần tử
Tất cả các toán tử nói trên đều có thể định nghĩa chồng trừ các toán tử sau:
. Chọn trực tiếp một thành phần
.* Gọi gián tiếp tới thành phần từ một biến đối tượng
:: Toán tử xác định phạm vi truy nhập
?: Toán tử điều kiện
Phụ lục 2
Hàm với đối số bất định trong C
Trong các giáo trình C thường chỉ hướng dẫn cách xây dựng hàm với các đối cố định. Mỗi đối cần có một tham số (cùng kiểu với nó) trong lời gọi hàm. Tuy nhiên một vài hàm chuẩn của C lại không như vậy, mà linh hoạt hơn, chẳng khi dùng hàm printf hay scanf thì số tham số mà ta cung cấp cho hàm là không cố định cả về số lượng lẫn kiểu cách. Ví dụ trong câu lệnh:
printf(“\n Tổng = %d “ , 3+4+5) ;
có 2 tham số, nhưng trong câu lệnh:
printf(“\n Hà Nội“ ) ;
chỉ có một tham số.
Như vậy cần phân biệt các khái niệm sau:
- Đối số cố định được khai báo trong dòng đầu của hàm, nó có tên và kiểu
- Tham số ứng với đối số cố định gọi là tham số cố định
- Đối bất định được khai báo bởi ba dấu chấm: bất định cả về số lượng và kiểu
- Tham số bất định (ứng với đối bất định) là một danh sách giá trị với số lượng và kiểu tuỳ ý (không xác định)
Trong phụ lục này sẽ trình bầy cách xây dựng các hàm với đối số bất định. Công cụ chủ yếu được dùng là con trỏ và danh sách.
1. Biến con trỏ
Biến con trỏ (hay con trỏ) dùng để chứa địa chỉ của biến, mảng, hàm, ... Có nhiều kiểu địa chỉ, vì vậy cũng có nhiều kiểu con trỏ. Biến con trỏ được khai báo theo mẫu:
Kiểu *Tên_biến_con_trỏ ;
Ví dụ:
float px ; // px là con trỏ thực
Các phép toán quan trọng trên con trỏ gồm:
+ Gán địa chỉ một vùng nhớ cho con trỏ (dùng toán tử gán, phép lấy địa chỉ, các hàm cấp phát bộ nhớ)
+ Truy nhập vào vùng nhớ thông qua con trỏ, dùng phép toán:
*Tên_con_trỏ
(Để ý ở đây có 2 vùng nhớ: vùng nhớ của biến con trỏ và vùng nhớ mà địa chỉ đầu của nó chứa trong biến con trỏ)
+ Cộng địa chỉ để con trỏ chứa địa chỉ của phần tử tiếp theo, dùng phép toán:
++ Tên_con_trỏ hoặc Tên_con_trỏ ++
Chú ý rằng các phép toán trên chỉ có thể thực hiện đối với con trỏ có kiểu.
2. Danh sách không cùng kiểu
Dùng con trỏ có kiểu chỉ quản lý được một danh sách giá trị cùng kiểu, ví dụ dẫy số thực, dẫy số nguyên, dẫy các cấu trúc,....
Khi cần quản lý một danh sách các giá trị không cùng kiểu ta phải dùng con trỏ không kiểu (void) khai báo như sau:
void * Tên_con_trỏ ;
Con trỏ void có thể chứa các địa chỉ có kiểu bất kỳ, và dùng để trỏ đến vùng nhớ chứa danh sách cần quản lý. Một chú ý quan trọng là mỗi khi gửi vào hay lấy ra một giá trị từ vùng nhớ, thì tuỳ theo kiểu giá trị mà ta phải dùng phép chuyển kiểu thích hợp đối với con trỏ. Ví dụ sau minh hoạ cách lập một danh sách gồm một số nguyên, một số thực và một chuỗi ký tự. Chúng ta cần một bộ nhớ để chứa số nguyên, số thực và địa chỉ chuỗi và dùng các con trỏ void để quản lý vùng nhớ này.
void *list , *p ; // Con trỏ list trỏ tới đầu danh sách
// p dùng để duyệt qua các phần tử của danh sách list=malloc(sizeof(int) + sizeof(float)+ sizeof(char*) ); p=list;
*((int*)p) = 12; // Đưa số nguyên 12 vào danh sách
((int*)p)++ ; // Chuyển sang phần tử tiếp theo
*((float*)p) = 3.14; // Đưa số thực 3.14 vào danh sách
((float*)p)++ ; // Chuyển sang phần tử tiếp theo
*((char**)p) = “HA NOI”; // Đưa địa chỉ chuỗi “HA NOI”
// vào danh sách
// Nhận các phần tử trong danh sách
p=list; // Về đầu danh sách
int a = *((int*)p); // Nhận phần tử thứ nhất ((int*)p)++ ; // Chuyển sang phần tử tiếp theo float x= *((float*)p); // Nhận phần tử thứ hai ((float*)p)++ ; // Chuyển sang phần tử tiếp theo
char *str = *((char**)p) ; // Nhận phần tử thứ ba
3. Hàm với đối số bất định
+ Đối bất định bao giờ cũng đặt sau cùng và được khai báo bằng dấu ba chấm. Ví dụ ví dụ hàm
void f(int n, char *s, ...) ;
có 2 đối cố định là n, s và đối bất định.
+ Để nhận được các tham số bất định trong lời gọi hàm ta cần lưu ý các điểm sau:
- Các tham số bất định chứa trong một danh sách. Để nhận được địa chỉ đầu danh sách ta dùng một con trỏ void và phép gán sau:
void *list ;
list = ... ;
- Dùng một tham số cố định kiểu chuỗi để quy định số lượng và kiểu của mỗi tham số trong danh sách, ví dụ:
“3i” hiểu là : tham số bất định gồm 3 giá trị int
“3f” hiểu là : tham số bất định gồm 3 giá trị float
“fiss” hiểu là có 4 tham số bất định có kiểu lần lượt là float, int, char*, char*
Một khi đã biết được địa chỉ đầu danh sách, biết được số lượng và kiểu của mỗi tham số , thì dễ dàng nhận được giá trị các tham số để sử dụng trong thân hàm.
Ví dụ sau đây minh hoạ cách xây dựng các hàm với tham số bất định. Hàm dùng để in các giá trị kiểu int, float và char. Hàm có một tham số cố định để cho biết có bao nhiêu giá trị và kiểu các giá trị cần in. Kiểu quy định như sau: i là int, f là float, s là char*. Tham số có 2 cách viết: lặp (gồm một hằng số nguyên và một chữ cái định kiểu) và liệt kê (một dẫy các chữ cái định kiểu). Ví dụ:
“4s” có nghĩa in 4 chuỗi
“siif” có nghĩa in một chuỗi, 2 giá trị nguyên và một giá trị thực:
#include 
#include 
#include 
#include 
#include 
#include 
void InDanhSachGiaTri(char *st,...)
{
void *list ; int gt_int ; float gt_float; char *gt_str; int n,i ;
char kieu;
int lap;
list = ... ; // list tro toi vung nho chua danh sach dia chi cac
// tham so lap = isdigit(st[0]) ; if (lap)
n=st[0] - '0' ; else n=strlen(st);
printf("\n n= %d lap = %d",n,lap); getch();
for(i=0;i<n;++i)
{
if(lap) kieu=st[1]; else
kieu = st[i];
printf("\nKieu= %c",kieu); getch();
switch(kieu)
{
case 'i' :
gt_int = *((int*)list);
if(!lap) ((int*)list)++ ;
printf("\nGia tri %d = %d",i,gt_int);
break;
case 'f' :
gt_float = (float) (*((double*)list));
if(!lap) ((double*)list)++ ;
printf("\nGia tri %d = %0.2f",i,gt_float);
break;
case 's' :
gt_str = *((char**)list) ;
if(!lap) ((char**)list)++ ;
printf("\nGia tri %d = %s",i,gt_str);
}
}
}
void main()
{
float x=3.14;
int a=123;
char *tp="HAI PHONG"; InDanhSachGiaTri("4i",a); InDanhSachGiaTri("4s","HA NOI");
InDanhSachGiaTri("ifsssffii", a, x, tp, tp,"QUY NHON", x, 6.28, a, 246);
InDanhSachGiaTri("4f",6.28);
getch();
}
4. Hàm không đối và hàm với đối bất định
Nhiều người nghĩ hàm khai báo như sau
void f();
là hàm không đối trong C. Trong C++ thì hiểu như thế là đúng, còn trong C thì đó là hàm có đối bất định (hàm không đối trong C khai báo như sau: f(void) ). Do không có
đối cố định nào cho biết về số lượng và kiểu của các tham số bất định, nên giải pháp ở đây là dùng các biến toàn bộ. Rõ ràng giải pháp này không không thuận tiện cho người dùng vì phải khai báo đúng tên biến toàn bộ và phải khởi gán giá trị cho nó trước khi gọi hàm. Ví dụ trình bầy một hàm chỉ có đối bất định dùng để tính max và min của các giá trị thực. Các tham số bất định được đưa vào theo trình tự sau: Địa chỉ chứa max, địa chỉ chứa min, các giá trị nguyên cần tính max, min. Chương trình dùng biến toàn bộ N để cho biết số giá trị nguyên cần tính max, min.
int N;
void maxmin()
{
void *lt = ... ;
float *max, *min , tg;
int i;
max = *((float**)lt)++;
min = *((float**)lt)++;
*max = *min = (float) *((double*)lt)++;
for(i=1;i<N;++i)
{
tg= (float) *((double*)lt)++; if(tg > *max) *max = tg; if(tg < *min) *min = tg;
}
}
TÀI LIỆU THAM KHẢO
1. G.S Phạm Văn Ất, C++ và lập trình hướng đối tượng, NXB Khoa học và kỹ thuật, Hà Nội, 2000.
2. G.S Phạm Văn Ất, Giáo trình cơ sở và nâng cao với kỹ thuật lập trình hướng đối tượng, NXB Khoa học và kỹ thuật, Hà Nội, 1999.
3. Claude Delannoy, Programmer en langage C++, EYROLLES.
4. Scott Robert Ladd, Turbo C++ Techniques and Applications, M&T Books.
H.M. Deitel & P.J. Deitel, C How to program.

File đính kèm:

  • docgiao_trinh_lap_trinh_huong_doi_tuong_lap_trinh_may_tinh.doc