Professional Documents
Culture Documents
Ngon-Ngu-Lap-Trinh - Vu-Song-Tung - Chapter4 - SV - (Cuuduongthancong - Com)
Ngon-Ngu-Lap-Trinh - Vu-Song-Tung - Chapter4 - SV - (Cuuduongthancong - Com)
.c
Lập trình
ng
co
an
Chương 4: Lớp và đối tượng
th
o ng
du
u
cu
2/10/2017
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Nội dung
4.1 Khái niệm
om
4.2 Định nghĩa lớp
4.3 Biến thành viên
.c
4.4 Hàm thành viên
ng
4.5 Kiểm soát truy nhập
co
4.6 Bài tập phần 1
an
4.7 Hàm tạo và hàm hủy
4.8 Hàm tạo bản sao
th
ng
4.9 Hàm toán tử gán
o
du
om
– Mô hình đại diện của một đối tượng vật lý:
.c
Person, student, employee, employer
Car, bus, vehicle,…
ng
– Đối tượng logic
co
Trend, report, button, window,…
an
Một đối tượng có:
th
– Các thuộc tính
ng
– Trạng thái
o
du
– Hành vi
u
– Căn cước
cu
– Ngữ nghĩa
om
tính, hành vi, quan hệ, ngữ nghĩa.
.c
Lớp là một kiểu dữ liệu mới có cấu trúc, trong đó việc
ng
truy nhập các biến thành viên được kiểm soát thông
co
qua các hàm thành viên.
Các dữ liệu của lớp biến thành viên
an
th
Các hàm của lớp hàm thành viên ng
Một biến của một lớp một đối tượng
o
du
u
cu
om
sruct Date{
//sử dụng
void main(){
int day, month, year;
.c
Date d;
};
set_date(d,32,13,2010);
void set_date(Date& date,int d, int m, int y){
ng
add_day(d,5);
date.day = d;
add_year(d,1);
date.month = m;
co
d.month = 13;
date.year = y;
}
}
an
void add_day(Date& date, int n){
th
date.day += n;
...
ng
}
Truy nhập biến
void add_month(Date& date, int n) ){
o
thành viên từ
du
date.month += n;
... bên ngoài
}
u
cu
om
Khi có sự thay đổi tên của các biến thành viên
.c
ng
người sử dụng phải thay đổi lại mã chương trình ứng
co
dụng
– Ví dụ: thay đổi lại cấu trúc Date
an
sruct Date{
th
int d, m, y; ng
};
o
– Thì đoạn mã sau sẽ có lỗi không biên dịch
du
Date d;
d.month = 10;
u
cu
om
class Date{
int day; Biến thành viên
.c
int month;
int year;
ng
public: Kiểm soát quyền
co
void set_date(int d, int m, int y){ truy nhập
day = d;
an
month = m;
year = y;
th
}
int get_day() { return day; } Hàm thành viên
ng
int get_month() { return month; }
o
int get_year() { return year; }
du
void add_year(int n) ){
year += n;
u
}
cu
...
};
om
void main(){
Date d;
.c
d.set_date(1,1,2010);
d.add_year(10);
ng
d.day = 10; //?? Có lỗi.
co
d.month = 10; //?? day, month, year là
d.year = 2009;//??
các biến thành viên
an
int i = d.day;//??
int day = d.get_day(); của Date thuộc kiểu
th
int month = d.get_month(); không được phép
int year = d.get_year();
ng
truy nhập từ bên
}
ngoài (kiểu private)
o
du
u
cu
om
class Date{ //Sử dụng
int d; void main{
.c
int m; Date d;
int y; d.set_date(1,1,2010);
ng
public: d.add_year(10);
int day = d.get_day();
co
void set_date(int _d, int _m, int _y){
d = _d; int month = d.get_month();
int year = d.get_year();
an
m = _m;
y = _y; }
th
}
int get_day() { return d; }
ng
int get_month() { return m; }
o
int get_year() { return y; }
du
void add_year(int n) ){
year += n;
Có sự khác
biệt
u
}
cu
... không?
};
om
int day,month, year; //khai báo tưng tự như cấu trúc
.c
...
};
ng
Mặc định các biến thành viên không truy nhập được từ bên
co
ngoài
an
Date d;
th
d.day = 10;; //Lỗi, vì biến thành viên day của Date thuộc kiểu private
ng
Có thể cho phép biến thành viên truy nhập từ bên ngoài bằng
o
du
cách chuyển thành biến public. Tuy nhiên, ít khi sử dụng như
vậy vì không còn che giấu dữ liệu
u
cu
class Date{
public:
int day,month, year; //truy nhập được từ bên ngoài
...
};
Chương 4: Lớp và đối tượng 10
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Truy nhập các biến thành viên thông qua các hàm
thành viên
class Date{
int day, month,year;
om
public: Hàm thành viên
int get_day() { return day; } để truy nhập biến
.c
void set_day(int d){ day = d; } thành viên
};
ng
co
Khởi tạo biến thành viên thông qua hàm tạo
class Date{
an
int day, month,year;
th
public:
ng
Date(int d, int m, int y){ //hàm tạo
o
day = d; month = m; year = y;
du
}
u
...
cu
};
om
int day, month,year;
.c
public: Khai báo và
int get_day() { return day; } định nghĩa
ng
void set_day(int d);
co
. . . Chỉ khai báo,
}; không định
an
void Date::set_day(int d){ nghĩa
th
day = d; ng
} Định nghĩa bên
ngoài phần khai
o
báo lớp
du
Để che giấu cách thực hiện, hàm thành viên thường được khai
u
báo trong tập tin đầu (*.h), phần định nghĩa được thực hiện
cu
trong tệp tin nguồn (*.cpp). Khi đóng gói thành thư viện, người
sử dụng chỉ cần tệp tin thư viện (*.lib) và tệp tin đầu (*.h),
không cần tệp tin nguồn (*.cpp)
om
class Date{
int day, month,year;
.c
public:
ng
int get_day();
co
void set_day(int d);
. . .
an
};
th
Định hàm thành viên trong tệp tin nguồn (*.cpp)
o ng
//tệp tin Date.cpp
du
day = d;
cu
}
void Date::get_day(){ return day;}
om
.c
void main{
Date d;
ng
d.set_date(1,1,2010);
Date *pd = &d;
co
//con trỏ pd trỏ vào đối tượng d
pd->set_date(1,1,2010);
an
Date *pd1 = new Date; //cấp phát bộ nhớ, gọi hàm tạo
pd1->set_day(10);
th
. . . ng
delete pd1; //hủy bộ nhớ
Date *pd2 = new Date[5];
o
du
. . .
cu
delete [] pd2;
}
om
thành viên của lớp và từ các bạn bè của lớp
.c
public: các thành viên công cộng, truy nhập được ở
ng
mọi nơi
co
protected: các thành viên không truy nhập được từ
an
bên ngoài, nhưng truy nhập được từ lớp dẫn xuất
th
Lớp dẫn xuất
ng
class A{ class B: public A{
o
du
protected: public:
int a; void g(){ Lớp cơ sở
u
}; }
};
om
người với các yêu cầu:
.c
– Tên có độ dài tối đa 50 ký tự
– Ngày, tháng, năm sinh có kiểu int (hoặc thuộc kiểu Date như
ng
đã gợi ý trong bài giảng).
co
– Quê quán có độ dài tối đa 100 ký tự
an
– Hàm nhập tên, ngày sinh, quê từ bán phím
th
– Hàm hiển thị thông tin ra màn hình
ng
– Hàm lấy tên, hàm gán tên
o
du
om
class Date{
int day, month,year;
.c
public:
int get_day() { return day; }
ng
void set_day(int d){ day = d; }
co
}; Câu hỏi:
void main(){
an
d.day = ?
Date d; d.month = ?
th
int i = d.get_date(); d.year = ?
}
ng
Làm thế nào để sau khi được tạo ra, đối tượng có
o
du
om
class Array{
int n; //số phần tử của array
.c
int *data; //mảng chứa giá trị các phần tử
public:
ng
...
};
co
an
Câu hỏi: làm thế nào để cấp phát bộ nhớ và hủy bộ
th
nhớ cho biến thành viên data một cách an toàn
ng
o
du
om
Hàm hủy: luôn được gọi khi đối tượng bị hủy
.c
Cú pháp:
ng
class A{
int a, b;
co
public:
A(){a = 0; b = 0;} 1
an
A(int _a){ a = _a;} 2
th
A(int _a, int _b){ a = _a; b = _b;} 3
~A();
ng
};
o
du
void main{
A a(); //gọi hàm tạo (?)
om
A a1(10); //gọi hàm tạo (?)
A a2(1,2); //gọi hàm tạo (?)
.c
} //gọi hàm hủy cho ?
ng
co
void f(A a){ gọi hàm tạo (?)
A b(0,0);
an
if(...){ gọi hàm tạo (?)
th
A c;
... gọi hàm hủy cho ?
ng
}
o
du
void main{
A *a = new A(10); //gọi hàm tạo (?)
. . . //sử dụng
delete a; //gọi hàm hủy
}
om
tạo như ví dụ trên?
.c
Giải pháp: sử dụng hàm tạo có tham biến mặc định
một lớp chỉ cần một hàm tạo duy nhất
ng
co
class A{
int a, b;
an
public:
th
A(int _a = 0, int _b = 0) { a = _a; b = _b;}
. . .
ng
};
o
du
void main{
A a1;
u
//a1.a = ?; a1.b = ?
cu
om
– Khởi tạo các trạng thái ban đầu cho đối tượng
Một lớp có thể có nhiều hàm tạo. Chúng khác nhau ở số lượng
.c
các tham số hoặc kiểu của các tham số.
ng
Nếu không định nghĩa hàm tạo thì compiler sẽ tự động sinh ra
co
một hàm tạo với mã thực thi là rỗng, dẫn đến:
– Trạng thái ban đầu của các biến thành viên là bất định
an
– Không cấp phát bộ nhớ động cho các biến thành viên dạng mảng
th
động
Hàm hủy là duy nhất
ng
Hàm hủy không bao giờ có đối
o
du
Nếu không định nghĩa hàm hủy thì compiler cũng tự động sinh
ra nhưng mã thực thi của hàm hủy này là rỗng.
u
cu
Khi sử dụng đối tượng động (có sử dụng toán tử new) thì luôn
phải nhớ hủy bộ nhớ đã cấp phát cho bộ nhớ động khi không cần
dùng đến chúng nữa (sử dụng toán tử delete)
Hàm tạo và hàm hủy có thể được định nghĩa bên ngoài phần
khai báo lớp.
Chương 4: Lớp và đối tượng 22
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Ví dụ về lớp Array
//sử dụng
//khai báo lớp Array void main(){
class Array{ Array a(5);
om
int n; Array *pa = new Array(5,1);
...
int *data;
delete pa;
.c
public: }
Array(int _n = 0, int _d = 0);
ng
~ Array();
co
. . .
}; Câu hỏi:
an
1. Các giá trị của mảng data của a, pa
//định nghĩa hàm tạo và hàm hủy bằng bao nhiêu?
th
Array :: Array(int _n, int _d){ 2. Không sử dụng delete pa có được
n = _n;
ng
không?
data = new int[n]; 3. Biến a được hủy khi nào?
o
for(int i = 0; i < n; i++)
du
data[i] = _d;
}
u
delete [] data;
}
om
(xem các ví dụ sau)
.c
Cú pháp chuẩn:
class A{
ng
Sao chép tham
int a, b;
số từ a1, a1
co
public:
A(const A& a1); không bị thay
an
. . . đổi do vô tình
};
//định nghĩa hàm sao chép
th
ng
A::A(const A& a1){
o
a = a1.a;
du
b = a1.b;
}
u
//sử dụng
cu
void main(){
A a; Gọi hàm tạo
A a1(a); bản sao
}
om
X x3 = x1;
X x4 = X(x1);
.c
– Khi truyền tham số qua giá trị cho một hàm
void f(X x) { ... }
ng
ở đây có sự gọi hàm tạo bản
void main(){
co
sao để sao chép nội dung của
X a; a để truyền vào cho tham biến
an
f(a); hình thức x của hàm f
th
} ng
- Khi một hàm trả về một đối tượng
o
X f() {
du
X x1;
. . . //thực hiện thuật toán
u
om
không cần định nghĩa hàm tạo bản sao
.c
Khi có tham biến được cấp phát động thì bắt buộc
ng
định nghĩa lại hàm tạo bản sao.
co
an
//khai báo lớp Array không có hàm tạo bản sao
th
class Array{
int n;
ng
int *data;
o
public:
du
om
... Hỏi: a.data[0] =
b.set_data(0,10);
.c
?
};
ng
Do không định nghĩa hàm tạo bản sao, nên ở đây gọi
co
hàm tạo bản sao mặc định do compiler sinh ra, hàm
an
tạo này có dạng:
th
Array :: Array(const Array & a){
ng
n = a.n;
o
data = a.data;
du
}
u
Khi sử dụng Array b(a); thì mảng data của a và b là một, nên
cu
om
Array :: Array(const Array & a) {
.c
n = a.n;
ng
data = new int[n];
for (int i=0; i < n; ++i)
co
data[i] = a.data[i];
an
}
th
Khi một lớp phải định nghĩa hàm hủy thì cũng cần
ng
thiết định nghĩa lại hàm tạo bản sao
o
du
Trong trường hợp muốn cấm sao chép thì ta khai báo
u
om
hàm thành viên dùng để trỏ đến đối tượng hiện tại
.c
Nói chung, con trỏ this ít khi được sử dụng tường
ng
minh, vì nó đã được ngầm sử dụng khi truy nhập vào
co
các thành phần dữ liệu. Nó thường được sử dụng khi
chúng ta muốn lấy địa chỉ của đối tượng hiện tại (như
an
để trỏ vào chính đối tượng đó)
th
o ng
du
u
cu
om
class A{
int a, b;
.c
public:
ng
A(int _a, int _b):a(_a), b(_b){} //hàm tạo
. . .
co
};
an
Gọi hàm toán tử gán (=).
void main(){ ở đây sẽ có:
th
A a(1,2); b.a = a.a
A b; OK
ng
b.b = a.b
b = a;
o
}
du
u
động sinh ra và gán từng bít (giống với hàm tạo bản
sao)
om
class Array{
.c
int n;
int *data;
ng
public:
Array(int _n = 0; int _d = 0) {...}
co
~ Array(){...}
an
...
};
Array a1;
a1.data = a.data
a1 = a;
u
}
cu
a1.data và a.data cùng trỏ vào một vùng nhớ kết quả tương
tự với trong trường hợp hàm tạo bản sao ở trên.
Trong trường hợp này cần định nghĩa hàm toán tử gán
Chương 4: Lớp và đối tượng 31
CuuDuongThanCong.com https://fb.com/tailieudientucntt
4.9 Hàm toán tử gán(…)
Cú pháp chuẩn hàm toán tử gán:
om
class A{
.c
...
public:
ng
A& operator=(const A&); //khái báo hàm toán tử gán
co
. . .
an
};
om
class Array{
.c
int n;
int *data;
ng
public:
Array(int _n = 0; int _d = 0) {...}
co
~Array(){...}
an
Array& operator=(const Array& a)
};
th
ng
Array& Array::operator=(const Array& a) {
if (n != a.n) {
o
du
delete [] data;
n = a.n;
u
}
for (int i=0; i < n; ++i)
data[i] = a.data[i];
return *this;
}
Chương 4: Lớp và đối tượng 33
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Bài tập
Định nghĩa lớp Array có các yêu cầu sau
om
– Hàm tạo, hàm hủy, hàm tạo bản sao, hàm toán tử gán
.c
– Các hàm cho phép nhập dữ liệu vào từ bàn phím và hiển thị
ra màn hình cho Array
ng
– Các hàm cho phép thay đổi/đọc giá trị của một phần tử nào
co
đó trong Array
an
– Viết chương trình chính minh họa cách sử dụng
th
o ng
du
u
cu
om
Vấn đề: Yêu cầu ghi lại số lượng các đối tượng được tạo ra từ lớp Date
void main(){
.c
Date d1(1,1,2010); // count++
ng
Date d2 = d1; // count++
co
…
}
an
Giải pháp: đưa biến count là một biến static của lớp Date
th
class Date{ Date::Date(int d, int m, int y){
ng
int day, month,year; day = d; month = m; year = y;
count++;
o
static int count;
du
public: }
Date(int d, int m, int y); Date::Date(const Date& d){
u
om
class A{ được các biến thành viên tĩnh và chỉ gọi
int n; được các hàm thành viên tĩnh khác. Nếu
.c
static int count; muốn truy nhập vào các biến thành viên
ng
public: của lớp thì phải khai báo một đối tượng
A():n(0){}
co
trung gian, vì trong hàm static không có
void f(); đối tượng ngầm định *this.
static void g();
an
. . .
th
}; ng
int A:: count = 0;
void A::f(){
o
n++;
du
void A::g(){
cho một đối tượng nào
cu
n = 2; //???
f(x); //???
count = 2; //OK
}
om
khi lớp chưa có một đối tượng nào
.c
Chung cho cả lớp, không phải của riêng mỗi đối tượng
ng
Để biểu thị thành phần tĩnh ta dùng “tên lớp :: tên
co
thành viên tĩnh” hoặc “tên đối tượng . Tên thành viên
an
tĩnh”
th
Được cấp phát bộ nhớ và khởi gán giá trị ban đầu bên
ng
ngoài khai báo lớp và ngoài các hàm (kể cả hàm
o
main)
du
u
cu
om
(mã số hóa đơn) và tienban với các hàm thực hiện
chức năng sau:
.c
– Hàm tạo hóa đơn
ng
– Hàm hủy hóa đơn
co
– Hàm sửa nội dung hóa đơn (sửa tiền bán)
an
– Hàm in ra tổng số hóa đơn và tổng số tiền bán sau các thao
th
tác tạo, hủy, sửa hóa đơn.
ng
– Viết hàm main để ứng dụng
o
du
u
cu
om
public:
.c
A():n(0){}
. . .
ng
};
class B{
co
int m;
an
public:
B():m(0){}
th
ngvoid f(A a){ a.n = 5;}//???
. . .
};
o
void g(A a){
du
}
cu
Làm thế nào để hàm phi thành viên, hàm thành viên của một
lớp khác có thể truy nhập trực tiếp vào biến thành viên của một
đối tượng?
Chương 4: Lớp và đối tượng 39
CuuDuongThanCong.com https://fb.com/tailieudientucntt
4.11 Friend(…)
Giải pháp: khai báo bạn bè – friend
om
Cái gì có thể là friend?
.c
– Hàm phi thành viên định nghĩa ở bên ngoài
ng
– Hàm thành viên của một lớp khác
co
– Cả lớp khác
an
class A{ class B{
int n; int m;
th
public:
ng public:
A():n(0){} B():m(0){}
friend void g(A a); void f(A a){ a.n = 5;}//OK
o
. . .
du
. . .
cu
};
void g(A a){
a.n = 10; //OK
}
om
int day, month,year;
public:
.c
Date(int d, int m, int y){
day = d; month = m; year = y;
ng
}
};
co
void main(){
an
int n = 5; Tại sao lỗi? Làm thế
cout<< n; //OK
th
nào để có thể sử
Date d(1,1,2010); dụng được như thế?
ng
cout<<d; //Lỗi
}
o
du
Biến n thuộc kiểu cơ sở, thư viện xuất/nhập đã hỗ trợ hàm toán
u
tử xuất ra màn hình cho các biến cơ sở đó. Biến d thuộc kiểu
cu
om
int day, month,year;
public:
.c
Date(int d=1, int m=1, int y=2010){
day = d; month = m; year = y;
ng
}
co
friend ostream& operator<<(ostream& os, const Date& d);
};
an
ostream& operator<<(ostream& os, const Date& d){
th
os<<“Ngay: ”<<d.day<<“-”<<d.month<<“-”<<d.year<<“\n”;
return os;
ng
}
o
void main(){
du
Date d(1,7,2010);
cout<<d;
u
}
cu
om
int real,imag;
public:
.c
Complex(int r, int i){
ng
real = r; imag = i;
}
co
};
void main(){
an
Complex a(1,2), b(5,6);
th
Complex c; ng
c = a + b; //Lỗi
}
o
du
om
public:
Complex(int r = 0, int i =0): real(r),imag(i) {}
.c
Complex operator+(const Complex& b) const {
ng
Complex z(real + b.real, imag + b.imag);
return z;
co
}
Complex operator-(const Complex& b) const {
an
return Complex(real - b.real, imag - b.imag);
th
}
Complex operator*(const Complex&) const;
ng
Complex operator/(const Complex&) const;
o
Complex& operator +=(const Complex&);
du
};
Yêu cầu: sinh viên hãy thực hiện nốt các hàm còn lại
Chương 4: Lớp và đối tượng 44
CuuDuongThanCong.com https://fb.com/tailieudientucntt
Nạp chồng các toán tử cho lớp complex sử dụng hàm bạn
#include <iostream.h>
class Complex{
int real,imag;
om
public:
Complex(int r = 0, int i =0): real(r),imag(i) {}
.c
friend Complex operator+(const Complex&, const Complex&) const;
ng
friend Complex operator-(const Complex&, const Complex&) const;
friend Complex operator*(const Complex&, const Complex&) const;
co
friend Complex operator/(const Complex&, const Complex&) const;
...
an
};
th
Complex operator+(const Complex& a,const Complex& b) const{
Complex z(a.real + b.real, a.imag + b.image);
ng
return z;
o
}
du
...
u
cu
om
– Các toán tử số học: ++ -- + - * / % += -= ...
&& || ! & &= | |= ...
.c
– Các toán tử logic, logic bit:
– Các toán tử so sánh: == != > < >= <=
ng
– Các toán tử thao tác bit: << >> >>= <<=
co
– Các toán tử khác: [] () -> * , ...
an
Các toán tử sau không nạp chồng được:
th ::
ng
– Toán tử truy nhập phạm vi (dấu hai chấm đúp)
.
o
– Toán tử truy nhập thành viên cấu trúc (dấu chấm)
du
om
sử dụng hàm thành viên, toán tử nhập/xuất cho lớp
số complex sử dụng hàm bạn
.c
2. Bổ sung các yêu cầu sau vào lớp Array
ng
co
– Các hàm nạp chồng toán tử [] (để gán hoặc lấy giá trị của
một phần tử),
an
– Nạp chồng toán tử +, -, * hai array, hoặc array với một số
th
– Định nghĩa toán tử nhập, xuất một array
ng
– Định nghĩa toán tử gọi hàm () để lấy ra giá trị max của
o
du
mảng.
u
cu