Bài 6 trình bày về Cấu trúc và Lớp. Nội dung cụ thể của chương này gồm có: Khái niệm về Cấu trúc (Struct), khai báo cấu trúc, khai báo biến kiểu cấu trúc, khởi tạo biến cấu trúc, truy cập đến thành phần của cấu trúc,...
Trang 1TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI
Trang 2Khái niệm về Cấu trúc (Struct)
Một tập hợp của một hoặc nhiều biến, có thể khác kiểu nhau,
được nhóm lại dưới một tên duy nhất cho tiện xử lý
Trong các ứng dụng về cơ sở dữ liệu, kiểu cấu trúc còn được
gọi là bản ghi
Việc định nghĩa cấu trúc sẽ tạo ra kiểu dữ liệu mới
Ví dụ:
Ví dụ:
Hồ sơ nhân viên: mỗi nhân viên được mô tả bởi một tập các
thuộc tính như: tên, địa chỉ, số CMT, lươngM Một trong số các
thuộc tính này lại có thể là một cấu trúc: tên có thể có vài thành
phần (họ, tên đệm, tên), địa chỉ và lương cũng có thể như vậy
Tài khoản ngân hàng: tên chủ tài khoản, tên tài khoản, số dư
tài khoản, loại tiền
Trang 3Khai báo cấu trúc
Khai báo một cấu trúc
struct <tên kiểu>
Trang 4Khai báo cấu trúc
Mỗi thành phần giống như một biến riêng của kiểu, nó gồm
kiểu và tên thành phần Một thành phần cũng còn được gọi là
trường
Phần tên của kiểu cấu trúc và phần danh sách biến cấu trúc có
thể có hoặc không Tuy nhiên trong khai báo kí tự kết thúc cuối
cùng phải là dấu chấm phẩy (;)
cùng phải là dấu chấm phẩy (;)
Các kiểu cấu trúc được phép khai báo lồng nhau, nghĩa là một
thành phần của kiểu cấu trúc có thể lại là một trường có kiểu cấu
trúc
Một biến có kiểu cấu trúc sẽ được phân bố bộ nhớ sao cho các
thực hiện của nó được sắp liên tục theo thứ tự xuất hiện trong
khai báo
Trang 5Khai báo biến kiểu cấu trúc
Khai báo ngay sau dấu ngoặc }, danh sách các biến;
struct { } x, y, z;
Khai báo như biến thông thường (trong C)
struct <tên cấu trúc> <danh sách biến>
Khai báo như biến thông thường (trong C++)
<tên cấu trúc> <danh sách biến>;
Trang 6Khởi tạo biến cấu trúc
Khởi tạo ngay định nghĩa của nó với danh sách các khởi tạo
Trang 7Truy cập đến thành phần của cấu trúc
Biến không phải con trỏ
tên_cấu_ trúc.thành_phần
Biến con trỏ:
tên_cấu_ trúc->thành_phần,(*tên_cấu_trúc).thành_phần
Trang 8Nếu khai báo screen là
Nếu khai báo screen là
rect screen;
thì
screen.pt1.xchỉ đến tọa độ x của thành phần pt1 của screen
Trang 9Hàm và Cấu trúc
Các thao tác hợp lệ duy nhất với một cấu trúc là
Sao chép nó hoặc gán cho nó,
Lấy địa chỉ qua &,
Truy xuất các thành phần của nó
Việc sao chép và gán bao gồm
Việc sao chép và gán bao gồm
Truyền đối số tới hàm
Trả giá trị từ hàm
Trang 10struct Sophuc// Khai báo kiểu số phức dùng chung
struct Sophuc// Khai báo kiểu số phức dùng chung
{
float thuc;
float ao;
};
Trang 11Hàm và Cấu trúc
Sophuc Cong(Sophuc x, Sophuc y)
{
Sophuc kq;
kq.thuc = x.thuc + y.thuc ;
kq.ao = x.ao + y.ao ;
Trang 12Hàm và Cấu trúc
void main(){
Sophuc x, y;
cout << "x = " ; cin >> x.thuc >> x.ao ;
cout << "y = " ; cin >> y.thuc >> y.ao ;
cout << "x + y = " ; In(Cong(x,y)) ;}
Ví dụ hàm trả về con trỏ cấu trúc
Ví dụ hàm trả về con trỏ cấu trúc
Sophuc* Tru(Sophuc x, Sophuc y){
Sophuc* kq=new Sophuc;
kq->thuc = x.thuc + y.thuc ;
kq->ao = x.ao + y.ao ;
return kq;
}
Trang 13Hàm và Cấu trúc
Hàm có đối số là cấu trúc
Là một biến cấu trúc
Là một con trỏ cấu trúc
Là một tham chiếu cấu trúc
Là một mảng cấu trúc hình thức hoặc con trỏ mảng
Trường hợp cấu trúc lớn, sử dụng con trỏ và tham chiếu sẽ hiệu
quả hơn việc phải sao chép cả cấu trúc
Con trỏ cấu trúc tương tương tự như con trỏ tới các biến thông
thường
Trang 16Kiểu Hợp
Kiểu hợp cũng có nhiều thành phần giống kiểu cấu trúc
Tuy nhiên, các thành phần của chúng sử dụng chung nhau một
vùng nhớ
Kích thước của một kiểu hợp là độ dài của trường lớn nhất và
việc
Thay đổi giá trị một thành phần sẽ ảnh hưởng đến tất cả các
Thay đổi giá trị một thành phần sẽ ảnh hưởng đến tất cả các
Trang 18Từ Khóa typedef
Một kiểu dữ liệu có thể được định nghĩa bằng cách sử
dụng từ khóa typedef
Nó không tạo ra một kiểu dữ liệu mới, mà định nghĩa
một tên mới cho một kiểu đã có
một tên mới cho một kiểu đã có
Cú pháp: typedef type tên;
Ví dụ: typedef float deci;
Trang 19Lập trình hướng đối tượng
Đối tượng: là một đơn vị đầy đủ được kết hợp bởi các
dữ liệu và chỉ thị
Đối tượng được chia thành hai thành phần: các
phương thức (hàm) và các thuộc tính (biến)
Phương thức: là phương tiện để sử dụng đối tượng,
Phương thức: là phương tiện để sử dụng đối tượng,
trong khi các thuộc tính sẽ mô tả đối tượng có tính chất
gì
Đối tượng được trừu tượng hóa qua việc định nghĩa
của các lớp
Trang 20Các đặc tính của lập trình hướng đối tượng
Tính trừu tượng (abstraction):
Bỏ qua một số khía cạnh thông tin, chỉ tập trung vào những
cốt lõi cần thiết
Mỗi đối tượng có thể hoàn tất các công việc một cách nội
bộ, báo cáo, thay đổi trạng thái của nó và liên lạc với các đối
tượng khác, không cần cho biết làm cách nào tiến hành
tượng khác, không cần cho biết làm cách nào tiến hành
được các thao tác (trừu tượng dự liệu)
Tính trừu tượng còn thể hiện qua việc một đối tượng ban
đầu có thể có một số đặc điểm chung cho nhiều đối tượng
khác như là sự mở rộng của nó nhưng bản thân đối tượng
này có thể không có các biện pháp thi hành (lớp trừu tượng
hay lớp cơ sở)
Trang 21Các đặc tính của lập trình hướng đối tượng
Tính đóng gói (encapsulation) và che giấu thông tin
(information hiding):
Tính chất này không cho phép người sử dụng các đối tượng
thay đổi trạng thái nội tại của một đối tượng
Chỉ có các phương thức nội tại của đối tượng cho phép thay
đổi trạng thái của nó
đổi trạng thái của nó
Tính đa hình (polymorphism):
Thông qua việc gửi các thông điệp (message)
Các phương thức dùng trả lời cho một thông điệp sẽ tùy theo
đối tượng mà thông điệp đó được gửi tới sẽ có phản ứng
khác nhau
Trang 22Các đặc tính của lập trình hướng đối tượng
Tính kế thừa (inheritance):
Cho phép một đối tượng có thể có sẵn các đặc tính mà đối
tượng khác đã có thông qua kế thừa
Cho phép các đối tượng chia sẻ hay mở rộng các đặc tính
sẵn có mà không phải tiến hành định nghĩa lại
sẵn có mà không phải tiến hành định nghĩa lại
Không phải ngôn ngữ hướng đối tượng nào cũng có tính
chất này
Trang 23Khái niệm về lớp (Class)
Một lớp bao gồm các hàm và dữ liệu có liên quan
Các hàm này là các hàm thành phần (member
function) hay còn là phương thức (method)
Giống như cấu trúc, lớp có thể xem như một kiểu dữ
liệu
Từ một lớp có thể tạo ra (bằng cách khai báo) nhiều
đối tượng (biến, mảng) khác nhau Mỗi đối tượng có
vùng nhớ riêng của mình
Trang 24Khai báo lớp (Class)
Trang 25Khai báo lớp (Class)
Việc khai báo một lớp không chiếm giữ bộ nhớ, chỉ các
đối tượng của lớp mới thực sự chiếm giữ bộ nhớ
Thuộc tính của lớp có thể là các biến, mảng, con trỏ có
kiểu chuẩn (int, float, char, char*, long, )
kiểu chuẩn (int, float, char, char*, long, )
Thuộc tính của lớp có thể là kiểu ngoài chuẩn đã định
nghĩa trước (struct, union, class, )
Thuộc tính của lớp không thể có kiểu của chính lớp đó,
nhưng có thể là con trỏ của lớp này
Trang 26Khai báo lớp (Class)- Các đặc tả truy cập
Các đặc tả truy cập này thay đổi các quyền truy cập
mà các thành phần khai báo sau chúng có được:
private: chỉ có thể truy cập từ bên trong thành phần
cùng lớp đó (trong thân các phương thức của lớp)
hoặc từ các thành phần bạn (friend) của nó
hoặc từ các thành phần bạn (friend) của nó
protected: như private, ngoài ra còn từ các thành
phần của các lớp dẫn xuất (lớp con) của lớp đó
public: có thể truy cập từ mọi nơi mà đối tượng hiển
thị
Mặc định của class là quyền truy cập private đối với
tất cả thành phần của nó
Trang 27Khai báo lớp (Class)- Các đặc tả truy cập
Nếu các thành phần dữ liệu đã khai báo là private thì
các hàm thành phần phải có ít nhất một vài hàm được
khai báo dạng public để có thể truy cập được, nếu không
toàn bộ lớp sẽ bị đóng kín và điều này không giúp gì cho
chương trình
chương trình
Cách khai báo lớp tương đối phổ biến là các thành
phần dữ liệu được ở dạng private và hàm thành phần
dưới dạng public
Trang 28Khai báo lớp (Class)- Dữ liệu thành phần
Khai báo như khai báo các thành phần trong kiểu cấu
trúc hay hợp
Bình thường được khai báo là private để bảo đảm tính
giấu kín, bảo vệ an toàn dữ liệu của lớp không cho phép
giấu kín, bảo vệ an toàn dữ liệu của lớp không cho phép
các hàm bên ngoài xâm nhập vào các dữ liệu này
Không được khai báo là auto, register hoặc extern
Kiểu: enum, kiểu dữ liệu có sẵn (chuẩn) hoặc người
dùng định nghĩa (struct, union, class)
Trang 29Khai báo lớp (Class)- Hàm thành phần
Hàm thành phần dùng để truy cập có kiểm soát vào thành
Trang 30Định nghĩa lớp (Class)- Hàm thành phần
Định nghĩa hàm: có thể được triển khai luôn trong thân lớp
hoặc bên ngoài lớp cùng toán tử phạm vi ::
(kiểu_trả_về tên_lớp::tên_hàm(…))
Hàm được định nghĩa bên trong lớp sẽ được tự động coi
là hàm thành phần inline bởi trình biên dịch
Hàm thành phần được phép truy xuất tới các dữ liệu thành
phần, kể cả dữ liệu kiểu private
Trang 31void displaypoint() ; //Hiện một ñiểm
//Ẩn một ñiểm, hàm ñịnh nghĩa trong khai báo
void hidepoint() { putpixel(x, y,getbkcolor());
} };
Trang 33Các hàm thành phần của lớp có quyền truy cập không
hạn chế vào thành phần dữ liệu của lớp đó
Việc truy cập vào các thành phần dữ liệu và hàm từ
ngoài phạm vi lớp do người lập trình kiểm soát
Trang 34Đối tượng, Mảng và con trỏ đối tượng của
lớp
Một đối tượng (object) là một thể nghiệm của lớp Lớp
là một định nghĩa của đối tượng
Chú ý: Lớp là một kiểu dữ liệu, đối tượng của lớp này chỉ
là một biến
Ví dụ:
point a;
point a;
Cách khai báo mảng đối tượng, con trỏ đối tượng cũng
giống như khai báo biến, mảng các kiểu khác (như int,
float, struct, union, )
Ví dụ:
point b[10], *c;
c= new point;
Trang 35Truy xuất thuộc tính của đối tượng
Mỗi thuộc tính đều thuộc về một đối tượng, không thể viết tên
thuộc tính một cách riêng rẽ mà bao giờ cũng phải có tên đối
a.x;// chỉ dùng ñược trong hàm thành phần
b=&a; b->y; // chỉ dùng ñược trong hàm thành phần
Chỉ có thể truy xuất thuộc tính private của đối tượng bằng các
hàm thành phần
Trang 36Sử dụng hàm thành phần của đối tượng
Cũng giống như hàm thông thường, hàm thành phần được
sử dụng thông qua lời gọi
Tuy nhiên trong lời gọi hàm thành phần bao giờ cũng phải có
tên đối tượng để chỉ rõ hàm thực hiện trên các thuộc tính của
đối tượng nào
Trang 37Đối của hàm thành phần, con trỏ this
Con trỏ this là con trỏ tới chính đối tượng của nó
Con trỏ this là đối thứ nhất của hàm thành phần
Các thuộc tính viết trong hàm inputdata() gọi bởi một đối
tượng được hiểu là thuộc chính đối tượng đó do con trỏ this trỏ
tới
Cách viết tường minh lại hàm inputdata()
Cách viết tường minh lại hàm inputdata()
void point::inputdata(){
cout <<"\n Nhap hoanh do va tung do cua diem:”;
cin >> this->x >>this-> y ;
cout << “\n Nhap ma mau cua diem: “;
cin >> this->m ;
}
Trang 38Đối của hàm thành phần, con trỏ this
Tham số truyền cho đối con trỏ this chính là địa chỉ của đối
tượng đi kèm với phương thức trong lời gọi phương thức
Ví dụ:
point a;
a.inputdata()
Trong trường hợp này tham số truyền cho con trỏ this chính
Trong trường hợp này tham số truyền cho con trỏ this chính
là địa chỉ của a:
this = &a
Con trỏ this còn được dùng trong các hàm thành phần cần trả
lại chính đối tượng có phương thức đang triển khai
Trang 39Đối tượng hằng và các hàm thành phần hằng
Đối tượng hằng là đối tượng được khai báo với từ khoá cons
Mọi ý định sửa đổi các đối tượng hằng đều bị chương trình
báo lỗi khi biên dịch
Các hàm thành phần "không sủa đổi dữ liệu của lớp", tức là
các hàm thành phần hằng và là các hàm được khai báo với từ
khoá const, mới được phép thực hiện trên các đối tượng hằng
khoá const, mới được phép thực hiện trên các đối tượng hằng
Khi viết các hàm thành phần của lớp, cần xác định ngay hàm
nào cần sửa hàm nào không cần sửa đổi dữ liệu của lớp và đặt
thêm từ khoá const tương ứng trong khai báo và định nghĩa
hàm
Trang 41Định nghĩa lớp- Hàm dựng (tạo)/ Cấu tử
Các đối tượng cần được khởi tạo dữ liệu thành phần hoặc
gán bộ nhớ động trong quá trình sinh ra để tránh việc trả lại các
giá trị không mong muốn trong quá trình thao tác chúng
Hàm dựng cũng là một hàm thành phần của lớp (nhưng là
hàm đặc biệt) được tự động gọi bất cứ khi nào một đối tượng
mới của lớp này được tạo ra
mới của lớp này được tạo ra
Chương trình dịch sẽ cấp phát bộ nhớ cho đối tượng sau đó
sẽ gọi đến hàm dựng
Hàm dựng sẽ khởi gán giá trị cho các thuộc tính của đối
tượng và có thể thực hiện một số công việc khác nhằm chuẩn
bị cho đối tượng mới
Trang 42Định nghĩa lớp- Hàm dựng (tạo)/ Cấu tử
Hàm dựng phải có tên giống tên lớp, không có giá trị trả về
(kể cả void)
Nếu không định nghĩa hàm dựng của một lớp, trình biên dịch
sẽ sinh ra hàm dựng ngầm định
Hàm dựng ngầm định không có đối và chỉ đơn thuần đặt
không vào mọi byte của biến thể nghiệm của một đối tượng
Một lớp có thể có nhiều hơn một hàm dựng (cùng tên, khác
bộ đối số)
Trang 43Định nghĩa lớp- Hàm dựng (tạo)/ Cấu tử
point()// hàm dựng không ñối
point()// hàm dựng không ñối
{x=0; y=0; m=1;}
//hàm dựng có ñối
point(int x1, int y1, int m1);
};
Trang 44Định nghĩa lớp- Hàm dựng (tạo)/ Cấu tử
point :: point(int x1, int y1, int m1)
{x = x1; y = y1; m = m1; }
Ví dụ:
point a; // Gọi tới hàm dựng không ñối
// Kết quả a.x = 0, a.y = 0, a.m = 1
point b(300, 100, 5);// Gọi tới hàm dựng có ñối
point b(300, 100, 5);// Gọi tới hàm dựng có ñối
// Kết quả b.x = 300, b.y = 100, b.m = 5
point c[5] ;// Gọi tới hàm dựng không ñối 5 lần
Các hàm có đối kiểu lớp, thì đối chỉ xem là các tham số hình
thức, vì vậy khai báo đối (trong dòng đầu của hàm) sẽ không
tạo ra đối tượng mới và do đó không gọi tới các hàm dựng
Trang 45point::point(const point& source)
point::point(const point& source)
Trang 46Định nghĩa lớp- Hàm dựng sao chép
Nếu không được định nghĩa, trình biên dịch sẽ tạo ra cấu tử
sao chép ngầm định Cấu tử này sao đối tượng nguồn theo từng
bit sang đối tượng mới
Hàm dựng sao chép trong ví dụ trên không khác gì hàm dựng
sao chép mặc định
sao chép mặc định
Khi lớp có các thuộc tính con trỏ hoặc tham chiếu, thì hàm
dựng sao chép mặc định chưa đáp ứng được yêu cầu (ví dụ sao
chép mặc định hai con trỏ của 2 đối tượng thì hai đối tượng
dùng chung bộ nhớ con trỏ-> hai đối tượng không độc lập)
Trang 47Hàm dựng sao chép tạo ra đối tượng mới trong khi toán tử
gán chỉ thay đổi giá trị của đối tượng hiện có
gán chỉ thay đổi giá trị của đối tượng hiện có
point& point::operator=(const point& source){
Trang 48Định nghĩa lớp- Hàm hủy/ Hủy tử
Hàm hủy thực hiện chức năng ngược lại với hàm dựng
Tự động gọi khi đối tượng bị hủy, hoặc do kết thúc phạm vi tồn
tại của nó hoặc do được cấp phát động và được giải phóng bằng
delete
Hủy tử phải có tên giống tên lớp, nhưng có thêm dấu ~ phía
trước, không có đối số và không có kiểu trả về (kể cả void)
trước, không có đối số và không có kiểu trả về (kể cả void)
point ::~ point()
{
}
Nếu không định nghĩa hàm hủy, thì một hàm hủy mặc định
không làm gì cả được phát sinh Đối với nhiều lớp thì hàm hủy
mặc định là đủ, và không cần đưa vào một hàm hủy mới
Trang 49Các lớp được định nghĩa với struct và union
Các lớp có thể định nghĩa bằng các từ khóa struct và union
Chỉ có một sự khác nhau là các thành phần của lớp được khai
báo với struct và union có quyền truy cập mặc định là public
Với union, nó chỉ chứa một thành phần dữ liệu tại một thời
Với union, nó chỉ chứa một thành phần dữ liệu tại một thời
điểm
Trang 50Quá tải/ Nạp chồng/ Định nghĩa lại các toán tử
Cú pháp:
type operator sign (parameters) { /* */ }
Ví dụ:
point operator=(point a);
point operator + (point a);
point operator - (point a);
point operator - (point a);