caùch keát hôïp döõ lieäu vaø phaàn thuû tuïc xöû lyù döõ lieäu vaøo trong moät thöïc theå duy nhaát, heä thoáng trôû thaønh moät sô ñoà phaân caáp duy nhaát caùc lôùp ñoái töôïng.... [r]
(1)Lập Trình Hướng Đối Tượng Lập Trình Hướng Đối Tượng Lập Trình Hướng Đối Tượng Lập Trình Hướng Đối Tượng
(2)Chương 1 Chương 1
(3)Giới thiệu Giới thiệu
Phân tích thiết kế lập trình theo hướng đối tượng sinh sau đẻ
muộn chứng tỏ ưu điểm vượt trội so với cách tiếp cận cổ điển
Trong lãnh vực phân tích thiết kế hệ thống, hướng tiếp cận
mẻ thu hút nhiều nhà nghiên cứu tên tuổi Nhiều kiểu mẫu, phương pháp luận, mô hình phân tích đưa với mức độ thành công khác
Ta nghiên cứu phương hướng phân tích theo quan điểm
Ta nghiên cứu phương hướng phân tích theo quan điểm
(4)Phương pháp phân tích mô hình Phương pháp phân tích mô hình
Phân tích dựa sở mơ hình hóa đối tượng
trong giới thực
Dùng mơ hình để xây dựng thiết kế không phụ
thuộc ngôn ngữ tổ chức xung quanh đối tượng
So với cách tổ chức cổ điển, mơ hình hố thiết kế
(5)Phương pháp phân tích mô hình Phương pháp phân tích mô hình
Các khái niệm giới thực mơ hình hố
bằng ký hiệu đồ hoạ mô tả đối tượng chúng (cấu trúc liệu hành vi) độc lập với ngôn ngữ
Các khái niệm ký hiệu dùng thống
nhất suốt trình phát triển hệ thống từ phân tích,
thiết cài đặt mà khơng cần thay đổi qua giai đoạn số phương pháp luận khác
đoạn số phương pháp luận khác
Không quan tâm đến chi tiết cài đặt giai đoạn
(6)Phương pháp phân tích mô hình Phương pháp phân tích mô hình
Các khái niệm liên quan đến máy tính đưa
ở bước mã hóa sau cùng, nhờ giữ uyển
(7)Phương pháp luận hướng đối tượng Phương pháp luận hướng đối tượng
Mơ hình hóa thiết kế theo hướng đối tượng lối
suy nghĩ vấn đề cần giải dùng mơ hình tổ chức xung quanh khái niệm giới thực
Trong hệ thống thông tin hướng đối tượng, thứ,
hay thứ, quan điểm đối tượng
hay thứ, quan điểm đối tượng
Mỗi đối tượng kết hợp hai thành phần đặc
(8)Phương pháp luận hướng đối tượng Phương pháp luận hướng đối tượng
Phương pháp luận theo quan điểm J.Rumbaugh bao
gồm xây dựng mơ hình hệ thống lãnh vực ứng dụng thêm chi tiết cài đặt trình thiết kế hệ thống
Các ký hiệu đồ họa sử dụng để biểu diễn khái
niệm hướng đối tượng niệm hướng đối tượng
Cách tiếp cận gọi kỹ thuật thiết kế mô
(9)Phương pháp luận hướng đối tượng Phương pháp luận hướng đối tượng
Kỹ thuật mơ hình hố OMT bao gồm bước:
Phân tích Thiết kế hệ thống
Thiết keá
(10)Các khái niệm hướng đối tượng Các khái niệm hướng đối tượng
Trừu tượng hố :
• Nhấn mạnh vào khía cạnh cốt yếu vốn có thực thể
và bỏ qua tính chất riêng biệt
• Sử dụng trừu tượng hố phân tích có nghĩa làm việc với
các khái niệm lãnh vực ứng dụng bỏ qua chi tiết cài đặt
• Hầu hết ngơn ngữ lập trình đại hổ trợ trừu tượng • Hầu hết ngơn ngữ lập trình đại hổ trợ trừu tượng
hố Nhưng trừu tượng hóa tận dụng tiếp cận đối tượng với tính kế thừa (inheritance) tính đa dạng
(11)Các khái niệm hướng đối tượng Các khái niệm hướng đối tượng
Tính đóng gói :
• Tách rời khía cạnh giao diện với bên đối tượng
với chi tiết cài đặt bên
• Tính đóng gói ngăn chặn khả chương trình trở nên
quá phụ thuộc lẫn dẫn tới hậu thay đổi nhỏ ảnh hưởng lớn đến tồn hệ thống
• Trong tiếp cận O.O khả kết hợp liệu hành vi • Trong tiếp cận O.O khả kết hợp liệu hành vi
(12)Các khái niệm hướng đối tượng Các khái niệm hướng đối tượng
Kết hợp liệu hành vi:
• Trong cách tiếp cận thủ tục cổ điển, hệ thống xây dựng
trên hai sơ đồ phân cấp chằng chịt: sơ đồ phân cấp liệu sơ đồ phân cấp thủ tục, liên hệ loại liệu thủ tục xử lý liệu mờ nhạt, dẫn đến khó khăn
trong việc sửa chữa, nâng cấp tương lai
• Cách tiếp cận O.O loại bỏ nhược điểm kể • Cách tiếp cận O.O loại bỏ nhược điểm kể
(13)Các khái niệm hướng đối tượng Các khái niệm hướng đối tượng
Sơ đồ phân cấp liệu
Kết hợp liệu hành vi
Sơ đồ phân cấp lớp Sơ đồ phân cấp liệu
(14)Đối tượng lớp Đối tượng lớp
Ta định nghĩa đối tượng "cái đó" có ý
nghĩa cho vấn đề ta quan tâm Đối tượng phục vụ hai mục đích: Giúp hiểu rõ giới thực cung cấp sở cho việc cài đặt máy
Mỗi đối tượng có nét nhận dạng để phân biệt
(15)Đối tượng lớp Đối tượng lớp
Các đối tượng có đặc tính tương tự gom
chung lại thành lớp đối tượng Ví dụ Người lớp đối tượng Một lớp đối tượng đặc trưng thuộc tính, hoạt động (hành vi)
Một thuộc tính (attribute) giá trị liệu cho
đối tượng lớp Tên, Tuổi, Cân nặng thuộc tính Người
tính Người
Một thao tác (operation) hàm hay phép bieán
(16)Sơ đồ đối tượng Sơ đồ đối tượng
Ta dùng sơ đồ đối tượng để mô tả lớp đối tượng Sơ
đồ đối tượng bao gồm sơ đồ lớp sơ đồ thể
Sơ đồ lớp mô tả lớp đối tượng hệ thống,
lớp đối tượng diễn tả hình chữ nhật có phần: phần đầu tên lớp, phần thứ hai mơ tả
thuộc tính phần thứ ba mô tả thao tác đối tượng lớp
(17)Sơ đồ lớp sơ đồ thể hiện Sơ đồ lớp sơ đồ thể hiện
Sinh viên Họ tên
Năm sinh Mã số
Điểm TB
(Sinh viên) Nguyễn Vaên A 1984
0610234T 9.2
Tên lớp
Thuộc tính
Điểm TB Đi học Đi thi
Phân loại
9.2
(18)Đối tượng lớp Đối tượng lớp
Cùng thao tác áp dụng cho nhiều lớp
đối tượng khác nhau, thao tác gọi có tính đa dạng (polymorphism)
Mỗi thao tác lớp đối tượng cụ thể tương ứng với
một cài đặt cụ thể khác Một cài đặt gọi phương thức (method)
Một đối tượng cụ thể thuộc lớp gọi thể
hiện (instance) lớp Joe Smith, 25 tuổi, nặng
Một đối tượng cụ thể thuộc lớp gọi thể
(19)Cài đặt lớp C++ Cài đặt lớp C++
Lớp C++ cài đặt kiểu liệu trừu tượng
người sử dụng định nghĩa, cho phép kết hợp liệu, phép toán, hàm liên quan để tạo đơn vị
chương trình Các lớp có đầy đủ ưu điểm tiện lợi kiểu liệu nội Lớp tách rời phần
giao diện (chỉ liên quan với người sử dụng) phần cài đặt lớp
đặt lớp
Lớp C++ cài đặt sử dụng từ khoá struct
(20)Ví dụ so sánh: Xây dựng kiểu liệu stack. Ví dụ so sánh: Xây dựng kiểu liệu stack.
1 Cách tiếp cận cổ điển: // Stack1.cpp :
//Dung cau truc va ham toan cuc
#include <iostream.h> typedef int bool;
typedef int Item;
const bool false = 0, true = 1; const bool false = 0, true = 1; struct Stack
{
Item *st, *top; int size;
(21)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
void StackInit(Stack *ps, int sz) {
ps->st = ps->top = new Item[ps->size=sz]; }
void StackCleanUp(Stack *ps) {
delete [] ps->st; delete [] ps->st; }
bool StackFull(Stack *ps) {
(22)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
bool StackEmpty(Stack *ps) {
return (ps->top <= ps->st); }
bool StackPush(Stack *ps, Item x) {
{
if (StackFull(ps)) return false; *ps->top++ = x;
(23)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
bool StackPop(Stack *ps, Item *px) {
if (StackEmpty(ps)) return false; *px = * ps->top;
(24)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
void XuatHe16(long n) {
static char hTab[] = “0123456789ABCDEF”; Stack s;
StackInit(&s,8); int x;
do {
StackPush(&s, n%16); StackPush(&s, n%16); n /= 16;
} while(n);
while(StackPop(&s,&x)) cout << hTab[x];
(25)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
Nhận xét:
Giải vấn đề
Khai báo cấu trúc liệu nằm riêng, hàm xử lý
liệu nằm riêng nơi khác Do khó theo dõi quản lý hệ thống lớn Vì khó bảo trì
Mọi thao tác có tham số trỏ đến đối
tượng cần thao tác Tư tưởng thể hàm hay
Mọi thao tác có tham số trỏ đến đối
tượng cần thao tác Tư tưởng thể hàm hay thủ tục đóng vai trị trọng tâm Đối tượng gởi đến cho hàm xử lý
Trình tự sử dụng qua bước: Khởi động, sử dụng thực
(26)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
2 Cách tiếp cận dùng hàm thành phần:
//
struct Stack {
Item *st, *top; int size;
void Init(int sz) {st = top = new Item[size=sz];}
Item[size=sz];}
void CleanUp() {if (st) delete [] st;} bool Full() const {return (top - st >= size);}
bool Empty() const {return (top <= st);} bool Push(Item x);
(27)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
bool Stack::Push(Item x) {
if (Full()) return false; *top++ = x;
return true; }
bool Stack::Pop(Item *px) {
if (Empty()) return false; *px = * top;
(28)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
void XuatHe16(long n) {
static char hTab[] = “0123456789ABCDEF”; Stack s;
s.Init(8); int x;
do {
s.Push(n%16); n /= 16;
} while(n);
while(s.Pop(&x)) cout << hTab[x]; s.CleanUp();
(29)Ví dụ so sánh (tt) Ví dụ so sánh (tt)
Nhận xét:
Giải vấn đề
Dữ liệu hàm xử lý liệu gom vào chỗ
bên cấu trúc Do dễ theo dõi quản lý, dễ bảo trì nâng cấp
Các thao tác bớt tham số so với cách tiếp cận
cổ điển Vì việc lập trình gọn Tư tưởng thể cổ điển Vì việc lập trình gọn Tư tưởng thể đối tượng đóng vai trị trọng tâm Đối tượng
thực thao tác
Trình tự sử dụng qua bước: Khởi động, sử dụng thực
(30)Các hàm thành phần. Các hàm thành phần.
Là hàm khai báo lớp Hàm thành phần
được định nghĩa bên bên lớp
Hàm thành phần có nghi thức giao tiếp giống với
hàm bình thường khác: có tên, danh sách tham số, giá trị trả
Gọi hàm thành phần phép toán dấu chấm (.)
dấu mũi tên (->) dấu mũi tên (->)
Stack s, *ps = &s; s.Init(10);
(31)Lớp Lớp
Trong cách tiếp cận dùng struct hàm thành phần,
người sử dụng có toàn quyên truy xuất, thay đổi
thành phần liệu đối tượng thuộc cấu trúc Ví dụ:
Stack s;
s.Init(10);
s.size = 100; // Nguy hiem for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
s.Push(i);
Vì vậy, ta khơng có an toàn liệu Lớp
phương tiện để khắc phục nhược điểm
Lớp có cách thay từ khoá struct từ khoá
(32)Lớp Lớp
Trong lớp thành phần riêng tư
(private) nghĩa giới bên ngồi khơng phép truy xuất Do có an tồn liệu
class Stack {
Item *st, *top; int size;
int size;
void Init(int sz) {st = top = new Item[size=sz];}
void CleanUp() {if (st) delete [] st;}
bool Full() const {return (top - st >= size);} bool Empty() const {return (top <= st);}
(33)Lớp Lớp
Phát biểu:
s.size = 100; // Bao sai
(34)Thuoäc tính truy xuất Thuộc tính truy xuất
Tuy nhiên lớp trở thành vô dụng hàm
thành phần trở thành private khơng dùng Điều khắc phục nhờ thuộc tính truy xuất
Thuộc tính truy xuất thành phần lớp rõ
phần chương trình phép truy xuất đến
(35)Thuộc tính truy xuất Thuộc tính truy xuaát
Các thành phần nội lớp, bao gồm liệu
các hàm phục vụ nội đặt phần private Các hàm nhằm mục đích cho người sử dụng dùng đặt phần public
(36)// Stack.h class Stack {
Item *st, *top; int size;
void Init(int sz) {st = top = new Item[size=sz];} void CleanUp() {delete [] st;}
public:
Stack(int sz = 20) {Init(sz);} Stack(int sz = 20) {Init(sz);} ~Stack() {delete [] st;}
bool Full() const {return (top - st >= size);}
bool Empty() const {return (top <= st);} bool Push(Item x);
(37)Ví dụ lớp thuộc tính truy xuất Ví dụ lớp thuộc tính truy xuất
// Stack.cpp
#include "stack.h"
bool Stack::Push(Item x) {
if (Full()) return false; *top++ = x;
return true; }
}
bool Stack::Pop(Item *px) {
(38)Ví dụ lớp thuộc tính truy xuất Ví dụ lớp thuộc tính truy xuất
// he16.cpp
#include "stack.h"
void XuatHe16(long n) {
static char hTab[] = “0123456789ABCDEF”; Stack s(8); int x;
do { {
s.Push(n%16); n /= 16;
} while(n);
while(s.Pop(&x))
(39)Sử dụng phạm vi truy xuất Sử dụng phạm vi truy xuất
Phạm vi truy xuất sử dụng cho phép ta kết
luận: Nhìn vào lớp thấy thao tác lớp
Người dùng bình thường khai thác hết chức
năng (public) lớp
Người dùng cao cấp thay đổi chi tiết cài đặt, cải
(40)Tự tham chiếu Tự tham chiếu
Là tham số ngầm định hàm thành phần trỏ đến đối
tượng Nhờ hàm thành phần biết thao tác đối tượng
Khi đối tượng gọi thao tác, địa đối tượng
được gởi cách ngầm định với tên this, tên thành phần đối tượng hiểu đối tượng có địa this
địa this naøy
bool Stack::Push(Item x) {
if (Full()) // if (this->Full()) return false;
*top++ = x; // this->top++ = x; return true;
(41)Phương thức thiết lập hủy bỏ Phương thức thiết lập hủy bỏ
Phương thức thiết lập huỷ bỏ xây dựng nhằm
mục đích khắc phục lỗi quên khởi động đối tượng khởi động dư Việc quên khởi động đối tượng thường gây lỗi khó tìm
Phương thức thiết lập hàm thành phần đặc biệt
tự động gọi đến đối tượng thuộc lớp tạo Người ta thường lợi dụng đặc tính để khởi tạo Người ta thường lợi dụng đặc tính để khởi động đối tượng
Phương thức thiết lập có tên trùng với tên lớp để phân
(42)Phương thức thiết lập hủy bỏ Phương thức thiết lập hủy bỏ
Có thể có nhiều phiên khác phương thức
thiết lập
Phương thức huỷ bỏ hàm thành phần đặc biệt tự
động gọi đến đối tượng bị huỷ Người ta thường lợi dụng đặc tính để dọn dẹp đối tượng
Phương thức huỷ bỏ bắt đầu dấu ngã (~) theo sau
bởi tên lớp để phân biệt với hàm thành phần tên lớp để phân biệt với hàm thành phần khác
(43)Phương thức thiết lập hủy bỏ Phương thức thiết lập hủy bỏ
typedef int Item; class Stack
{
Item *st, *top; int size;
void Init(int sz);
void CleanUp() {delete [] st;} public:
Stack(int sz = 20) {Init(sz);} Stack(int sz = 20) {Init(sz);} ~Stack() {CleanUp();}
bool Full() const {return (top - st >= size);}
bool Empty() const {return (top <= st);} bool Push(Item x);
(44)Hàm bạn (friends) Hàm bạn (friends)
Nguyên tắc chung thao tác lớp thơng qua
hàm thành phần Tuy nhiên có trường hợp ngoại lệ, hàm phải thao tác hai lớp
Hàm bạn lớp hàm khai báo bên
ngoài phép truy xuất thành phần riêng tư lớp
Ta làm hàm trở thành hàm bạn lớp cách Ta làm hàm trở thành hàm bạn lớp cách
đưa khai báo hàm vào lớp, thêm từ khoá friend đầu
Ta dùng hàm bạn trường hợp hàm phải hàm
(45)Hàm thành phần hằng Hàm thành phần hằng
Hàm thành phần hàm thành phần áp
dụng cho đối tượng
Ta qui định hàm thành phần cách
thêm từ khố const vào cuối khai báo
Ta khai báo hàm thành phần không thay
(46)Hàm thành phần hằng Hàm thành phần hằng
inline char *strdup(const char *s) {
return strcpy(new char[strlen(s) + 1], s); }
class string {
char *p; public:
string(char *s = "") {p = strdup(s);} ~string() {delete [] p;}
string(const string &s2) {p = strdup(s2.p);} void Output() const {cout << p;}
(47)Hàm thành phần hằng Hàm thành phần hằng
void main() {
const string Truong("DH BC TDT"); string s("ABCdef");
s.Output(); s.ToLower(); s.Output(); s.Output();
Truong.Output();
(48)Thành phần tónh (static members) Thành phần tónh (static members)
Thành phần liệu tĩnh thành phần liệu dùng
chung cho đối tượng thuộc lớp
Hàm thành phần tĩnh hàm thành phần hoạt
động khơng cần liệu đối tượng, nói cách khác, khơng cần đối tượng
Ta dùng hàm thành phần tĩnh thay hàm tồn cục
nó có liên quan mật thiết với lớp có liên quan mật thiết với lớp
Ta dùng hàm thành phần tĩnh để tạo đối tượng có
(49)Ví dụ thành phần tónh: CDate Ví dụ thành phần tónh: CDate typedef int bool;
const bool false = 0, true = 1; class CDate
{
static int dayTab[][13]; int day, month, year;
public: public:
static bool LeapYear(int y) {return y%400 == || y%4==0 && y%100 != 0;}
static int DayOfMonth(int m, int y);
(50)Ví dụ thành phần tónh : CDate Ví dụ thành phần tónh : CDate int CDate::dayTab[][13] =
{
{0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31} };
int CDate::DayOfMonth(int m, int y) {
return dayTab[LeapYear(y)][m]; return dayTab[LeapYear(y)][m]; }
bool betw(int x, int a, int b) {
(51)Ví dụ thành phần tónh : CDate Ví dụ thành phần tónh : CDate bool CDate::ValidDate(int d, int m, int y) {
return betw(m,1,12) &&
betw(d,1,DayOfMonth(m,y)); }
void CDate::Input() {
int d,m,y; int d,m,y;
cin >> d >> m >> y;
while (!ValidDate(d,m,y)) {
cout << "Please enter a valid date: "; cin >> d >> m >> y;
(52)2.3 Thiết lập huỷ bỏ đối tượng 2.3 Thiết lập huỷ bỏ đối tượng Ta cần kiểm soát phương thức thiết lập gọi, phương thức huỷ bỏ gọi
• Khi đối tượng thiết lập gọi? Khi đối tượng
được tạo
• Khi phương thức huỷ bỏ gọi? Khi đối tượng bị
huỷ
Thời gian từ đối tượng tạo đến bị huỷ
• Thời gian từ đối tượng tạo đến bị huỷ
đi gọi thời gian sống
Vậy vấn đề xác định phương thức thiết lập
huỷ bỏ gọi trở thành:
(53)Thiết lập huỷ bỏ đối tượng Thiết lập huỷ bỏ đối tượng
Thời gian sống đối tượng khác tuỳ thuộc đối
tượng thuộc lớp lưu trữ (storage class) Trong C++ có lớp lưu trữ sau:
auto global static
free stored free stored
Ta xét loại sau: Đối tượng tự động
Đối tượng toàn cục Đối tượng tĩnh
(54)Đối tượng tự động Đối tượng tự động
Đối tượng tự động (automatic objects) đối tượng
tự động sinh tự động bị huỷ
Đối tượng địa phương
• Là biến khai báo, định nghĩa bên khối
• Nó tự động sinh chương trình thực ngang dịng
lệnh chứa định nghĩa bị huỷ sau chương trình hồn tất khối chứa định nghĩa
khối chứa định nghĩa
Khi khởi động đối tượng đối tượng
kiểu, chế tạo đối tượng chép bit, đối tượng khởi động chia sẻ tài
(55)Đối tượng biến địa phương Đối tượng biến địa phương #include <iostream.h>
#include <string.h>
char *strdup(const char *s) {
return strcpy(new char[strlen(s) + 1], s); }
class string class string {
char *p; public:
string(char *s = "") {p = strdup(s);}
(56)void main() {
string a("Nguyen Van A");
string b = a; // String b(a) a.Output(); cout << "\n";
(57)Xuất liệu thực đoạn chương trình trên:
Nguyen Van A Nguyen Van A delete 0x0f06 delete 0x0f06
Đối tượng b có nội dung vật lý giống với a, nghĩa dùng
(58)Đối tượng tham số truyền giá trị Đối tượng tham số truyền giá trị
Đối tượng tham số hàm, truyền giá trị tham
số hình thức tham số thực sự, nên có nội dung vật lý giống tham số thực chế chép bit
extern char *strdup(const char *s); class String
{
char *p; char *p; public:
String(char *s = "") {p = strdup(s);}
~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;}
(59)Đối tượng tham số truyền giá trị Đối tượng tham số truyền giá trị
bool String::Compare(String s) const {
return strcmp(p,s.p); }
void main() {
String a("Nguyen Van A"); String b("Le Van Beo"); int c = a.Compare(b);
(60)Đối tượng tham số truyền giá trị Đối tượng tham số truyền giá trị
Khi thực đoạn chương trình trên, ta xuất liệu
(có thể thay đổi lần thực khác máy khác):
delete 0x0f34 a > b
(61)Đối tượng giá trị trả về Đối tượng giá trị trả về
extern char *strdup(const char *s); class String
{
char *p; public:
String(char *s = "") {p = strdup(s);}
~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;}
delete [] p;}
void Output() const {cout << p;} bool Compare(String s) const;
(62)Đối tượng giá trị trả về Đối tượng giá trị trả về
String String::UpCase() const {
String r = *this; strupr(r.p);
return r; }
void main() {
{
clrscr();
String a("Nguyen Van A");
cout << "a = "; a.Output(); cout << "\n"; String A;
A = a.UpCase();
(63)Đối tượng giá trị trả về Đối tượng giá trị trả về
Khi thực đoạn chương trình trên, ta xuât liệu
a = Nguyen Van A delete 0x0f36 delete 0x0f36 a = 2Ô2ÔEN VAN A A = 2Ô2ÔEN VAN A delete 0x0f36 delete 0x0f36
Null pointer assignment
(64)Đối tượng giá trị trả về Đối tượng giá trị trả về
Các lỗi sai gây đoạn chương trình chép đối tượng (phát biểu String r = *this), đối tượng giá trị trả phép gán (A = a.Upcase)
Ta khắc phục lỗi gây phép gán cách
thay hai phát biểu khai báo A gán phát biểu khởi động:
(65)Đối tượng giá trị trả về Đối tượng giá trị trả về
void main() {
clrscr();
String a("Nguyen Van A");
cout << "a = "; a.Output(); cout << "\n"; String A = a.UpCase();
cout << "a = "; a.Output(); cout << "\n"; cout << "A = "; a.Output(); cout << "\n"; }
(66)Đối tượng giá trị trả về Đối tượng giá trị trả về
Xuất liệu trường hợp a = Nguyen Van A
delete 0x0d32
a = NGUYEN VAN A A = NGUYEN VAN A delete 0x0d32
delete 0x0d32 delete 0x0d32
(67)Phương thức thiết lập chép Phương thức thiết lập chép
Các lỗi sai nêu gây chép đối tượng, ta có
thể khắc phục cách “dạy” trình biên dịch chép đối tượng cách luận lý thay chép bit theo nghĩa vật lý Điều thực nhờ
phương thức thiết lập chép
Phương thức thiết lập chép phương thức thiết lập
(68)Phương thức thiết lập chép Phương thức thiết lập chép
Phương thức thiết lập chép thực chép theo
nghĩa logic, thông thường tạo nên tài nguyên (sao chép sâu)
Phương thức thiết lập chép chia sẻ tài
nguyên cho đối tượng (sao chép nông) Trong trường hợp này, cần có chế để kiểm sốt sử huỷ bỏ đối
(69)Phương thức thiết lập chép Phương thức thiết lập chép extern char *strdup(const char *s);
class String {
char *p; public:
String(char *s = "") {p = strdup(s);} String(const String &s) {p =
strdup(s.p);} strdup(s.p);}
~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;}
void Output() const {cout << p;} bool Compare(String s) const;
(70)Phương thức thiết lập chép Phương thức thiết lập chép
bool String::Compare(String s) const {
return strcmp(p,s.p); }
String String::UpCase() const {
String r = *this; String r = *this; strupr(r.p);
(71)Phương thức thiết lập chép Phương thức thiết lập chép void main()
{
clrscr();
String a("Nguyen Van A"); String b("Le Van Beo"); String aa = a;
int c = a.Compare(b);
cout << (c > ? "a > b" : c == ? "a = b" : "a < b") << "\n";
cout << "a = "; a.Output(); cout << "\n"; String A = a.UpCase();
(72)Phương thức thiết lập chép Phương thức thiết lập chép
Xuất liệu trường hợp sau: delete 0x0d84
a > b
a = Nguyen Van A delete 0x0d84
a = Nguyen Van A A = NGUYEN VAN A A = NGUYEN VAN A delete 0x0d96
delete 0x0d72 delete 0x0d62 delete 0x0d50
Mỗi đối tượng có tài nguyên riêng nên không xảy
(73)Phương thức thiết lập chép Phương thức thiết lập chép
Tham số phương thức thiết lập chép bắt buộc
tham chieáu
Phương thức thiết lập chép dùng để
chép nông, tài nguyên chia sẻ có biến đếm để kiểm sốt
Lưu ý:
Nếu đối tượng khơng có tài ngun riêng khơng cần
Nếu đối tượng khơng có tài ngun riêng khơng cần
phương thức thiết lập chép
Khi truyền tham số đối tượng thuộc lớp có phương
(74)Sao chép nông chép sâu Sao chép nông chép sâu
Dùng phương thức thiết lập chép trên,
đối tượng có tài nguyên riêng chép sâu
Ta chép nông cách chia sẻ tài nguyên
và dùng biến đếm để kiểm soát số thể đối tượng có chia sẻ tài nguyên
Khi đối tượng thay đổi nội dung, phải tách
(75)Ví dụ chép nông Ví dụ chép nông extern char *strdup(const char *s);
class StringRep {
friend class String; char *p;
int n;
StringRep(const char *s) {p = strdup(s); n = 1;} ~StringRep() {cout << "delete ” << (void *)p << ~StringRep() {cout << "delete ” << (void *)p <<
(76)Ví dụ chép nông Ví dụ chép nông
class String {
StringRep *rep; public:
String(const char *s = "") {rep = new StringRep(s);}
String(const String &s) {rep = s.rep; rep->n++;}
rep->n++;} ~String();
void Output() const {cout << rep->p;} bool Compare(String s) const;
String UpCase() const; void ToUpper();
(77)Ví dụ chép nông Ví dụ chép nông
String::~String() {
if ( rep->n <= 0) delete rep;
}
bool String::Compare(String s) const {
return strcmp(rep->p,s.rep->p); return strcmp(rep->p,s.rep->p); }
String String::UpCase() const {
(78)Ví dụ chép nông Ví dụ chép nông void main()
{
clrscr();
String a("Nguyen Van A"); String b("Le Van Beo"); String aa = a;
int c = a.Compare(b);
cout << (c > ? "a > b" : c == ? "a = b" : "a cout << (c > ? "a > b" : c == ? "a = b" : "a < b") << "\n";
cout << "a = "; a.Output(); cout << "\n"; String A = a.UpCase();
(79)Ví dụ chép nông Ví dụ chép nông
Xuất liệu thực đoạn chương trình sau: a > b
a = Nguyen Van A a = Nguyen Van A A = NGUYEN VAN A delete 0x0d8a
(80)Ví dụ chép nông Ví dụ chép nông
delete 0x0d84 a > b
a = Nguyen Van A delete 0x0d84
a > b
a = Nguyen Van A a = Nguyen Van A A = NGUYEN VAN A
So sánh với chép sâu: Bên trái, dùng chép sâu, bên phải dùng chép nông
delete 0x0d84
a = Nguyen Van A A = NGUYEN VAN A delete 0x0d96
delete 0x0d72 delete 0x0d62 delete 0x0d50
A = NGUYEN VAN A delete 0x0d8a
(81)Đối tượng tĩnh Đối tượng tĩnh
Đối tượng tĩnh đối tượng định nghĩa tồn
cục, định nghĩa có thêm từ khố static (toàn cục địa phương)
Đối tượng toàn cục tĩnh toàn cục tạo
bắt đầu chương trình bị huỷ kết thúc chương trình
Đối tượng tĩnh địa phương tạo chương trình Đối tượng tĩnh địa phương tạo chương trình
(82)Đối tượng tĩnh Đối tượng tĩnh
Trình tự thực chương trình gồm:
• Gọi phương thức thiết lập cho đối tượng toàn cục • Thực hàm main()
• Gọi phương thức huỷ bỏ cho đối tượng toàn cục
(83)Ví dụ đối tượng tồn cục Ví dụ đối tượng tồn cục
Xét đoạn chương trình sau: #include <iostream.h> void main()
{
cout << "Hello, world.\n"; }
Hãy sửa lại đoạn chương trình để có xuất liệu: Hãy sửa lại đoạn chương trình để có xuất liệu:
Entering a C++ program saying Hello, world
And then exitting…
(84)Ví dụ đối tượng tồn cục Ví dụ đối tượng tồn cục
Đoạn chương trình sửa lại sau: #include <iostream.h>
void main() {
cout << "Hello, world.\n"; }
class Dummy class Dummy {
public:
Dummy() {cout << "Entering a C++ program saying \n";}
~Dummy() {cout << "And then exitting ";} };
(85)Đối tượng thành phần lớp Đối tượng thành phần lớp
Đối tượng thành phần đối tượng khác,
một đối tượng thuộc lớp “lớn” tạo ra, thành phần tạo Phương thức thiết lập (nếu có) tự động gọi cho đối tượng thành phần
Nếu đối tượng thành phần phải cung cấp tham số
(86)Đối tượng thành phần lớp Đối tượng thành phần lớp
Cú pháp để khởi động đối tượng thành phần dùng
dấu hai chấm (:) theo sau tên thành phần tham số khởi động
Khi đối tượng kết hợp bị huỷ đối tượng thành
(87)Đối tượng thành phần lớp Đối tượng thành phần lớp
class Diem {
double x,y; public:
Diem(double xx, double yy) {x = xx; y = yy;} //
};
class TamGiac {
{
Diem A,B,C; public:
void Ve() const; //
};
(88)Đối tượng thành phần lớp Đối tượng thành phần lớp
class String {
char *p; public:
String(char *s) {p = strdup(s);}
String(const String &s) {p = strdup(s.p);}
~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;
// };
};
class SinhVien {
String MaSo; String HoTen; int NamSinh; public:
};
(89)Đối tượng thành phần - thiết lập Đối tượng thành phần - thiết lập class Diem
{
double x,y; public:
Diem(double xx, double yy {x = xx; y = yy;} //
(90)Khởi động đối tượng thành phần Khởi động đối tượng thành phần
class TamGiac {
Diem A,B,C; public:
TamGiac(double xA, double yA, double xB, double yB, double xC, double yC):A(xA,yA),
B(xB,yB),C(xC,yC){} void Ve() const;
void Ve() const; //
};
(91)Đối tượng thành phần lớp Đối tượng thành phần lớp class String
{
char *p; public:
String(char *s) {p = strdup(s);}
String(const String &s) {p = strdup(s.p);} ~String() {cout << "delete "<< (void *)p <<
"\n"; delete [] p; "\n"; delete [] p; //
(92)Khởi động đối tượng thành phần Khởi động đối tượng thành phần class SinhVien
{
String MaSo; String HoTen; int NamSinh; public:
SinhVien(char *ht, char *ms, int ns):HoTen(ht), MaSo(ms){NamSinh = ns;}
MaSo(ms){NamSinh = ns;} //
};
(93)Khởi động đối tượng thành phần Khởi động đối tượng thành phần
Cú pháp dùng dấu hai chấm dùng cho đối
tượng thành phần thuộc kiểu class Diem
{
double x,y; public:
Diem(double xx, double yy):x(xx), y(yy){} //
}; };
class SinhVien {
String MaSo, HoTen; int NamSinh;
public:
(94)Đối tượng thành phần - Huỷ bỏ Đối tượng thành phần - Huỷ bỏ
Khi đối tượng kết hợp bị huỷ bỏ, đối tượng thành phần
của bị huỷ bỏ class SinhVien
{
String MaSo, HoTen; int NamSinh;
int SoMon; double *Diem; public:
public:
SinhVien(char *ht, char *ms, int ns, int sm, double *d); ~SinhVien() {delete [] Diem;}
// };
SinhVien::SinhVien(char *ht, char *ms, int ns, int sm, double *d):HoTen(ht), MaSo(ms), NamSinh(ns), SoMon(sm) {
(95)Đối tượng thành phần mảng Đối tượng thành phần mảng
Khi mảng tạo ra, phần tử
được tạo ra, phương thức thiết lập gọi cho phần tử
Vì khơng thể cung cấp tham số khởi động cho tất
phần tử mảng nên khai báo mảng, đối
tượng mảng phải có khả tự khởi động, nghĩa thiết lập khơng cần tham số
là thiết lập không cần tham số
Đối tượng có khả tự khởi động trường
hợp sau:
• Lớp khơng có phương thức thiết lập
(96)Đối tượng thành phần mảng Đối tượng thành phần mảng
class Diem {
double x,y; public:
Diem(double xx, double yy):x(xx), y(yy) {}
void Set(double xx, double yy) {x = xx, y = yy;} //
};
class String class String {
char *p; public:
String(char *s) {p = strdup(s);}
String(const String &s) {p = strdup(s.p);} ~String() {cout << "delete "<< (void *)p <<
(97)Đối tượng thành phần mảng Đối tượng thành phần mảng
class SinhVien {
String MaSo; String HoTen; int NamSinh; public:
SinhVien(char *ht, char *ms, int ns):HoTen(ht), MaSo(ms), NamSinh(ns){}
MaSo(ms), NamSinh(ns){} //
};
String as[3]; // Bao sai
Diem ad[5]; // Bao sai
(98)Phương thức thiết lập với tham số có giá trị mặc nhiên
Phương thức thiết lập với tham số có giá trị mặc nhiên
class Diem {
double x,y; public:
Diem(double xx = 0, double yy = 0):x(xx), y(yy){}
void Set(double xx, double yy) {x = xx, y = yy;} //
// };
class String {
char *p; public:
String(char *s = “”) {p = strdup(s);}
(99)Dùng phương thức thiết lập với tham số có giá trị mặc nhiên
Dùng phương thức thiết lập với tham số có giá trị mặc nhiên
class SinhVien {
String MaSo; String HoTen; int NamSinh; public:
SinhVien(char *ht = “Nguyen Van A”, char *ms = “19920014”, int ns =
“19920014”, int ns =
1982):HoTen(ht), MaSo(ms), NamSinh(ns){}
// };
(100)Dùng phương thức thiết lập không tham số Dùng phương thức thiết lập không tham số
class Diem {
double x,y; public:
Diem(double xx, double yy):x(xx), y(yy){} Diem():x(0), y(0){}
// };
};
class String {
char *p; public:
String(char *s) {p = strdup(s);} String() {p = strdup(“”);}
(101)Dùng phương thức thiết lập không tham số
Dùng phương thức thiết lập không tham số
class SinhVien {
String MaSo; String HoTen; int NamSinh; public:
SinhVien(char *ht, char *ms, int SinhVien(char *ht, char *ms, int
ns):HoTen(ht), MaSo(ms), NamSinh(ns){}
SinhVien():HoTen(“Nguyen Van A”),
MaSo(“19920014”), NamSinh(1982){} //
(102)Đối tượng cấp phát động Đối tượng cấp phát động
Đối tượng cấp phát động đối tượng tạo
ra phép toán new bị huỷ phép toán delete
Phép toán new cấp đối tượng vùng heap (hay vùng
free store) gọi phương thức thiết lập cho đối tượng cấp
Dùng new cấp đối tượng dùng delete để Dùng new cấp đối tượng dùng delete để
huỷ đối tượng
Dùng new delete cấp nhiều đối tượng
(103)Đối tượng cấp phát động Đối tượng cấp phát động
class String {
char *p; public:
String(char *s) {p = strdup(s);}
String(const String &s) {p = strdup(s.p);} ~String() {delete [] p;}
// };
};
class Diem {
double x,y; public:
(104)Cấp huỷ đối tượng Cấp huỷ đối tượng
int *pi = new int;
int *pj = new int(15);
Diem *pd = new Diem(20,40);
String *pa = new String("Nguyen Van A"); //
(105)Cấp huỷ nhiều đối tượng Cấp huỷ nhiều đối tượng
Trong trường hợp cấp nhiều đối tượng, ta cung
cấp tham số cho phần tử cấp:
int *pai = new int[10];
Diem *pad = new Diem[5]; // Bao sai String *pas = new String[5]; // Bao sai //
Thông báo lỗi cho đoạn chương trình sau: Thơng báo lỗi cho đoạn chương trình sau:
Cannot find default constructor to initialize array element of type 'Diem'
Cannot find default constructor to initialize array element of type String’
(106)Cấp huỷ nhiều đối tượng Cấp huỷ nhiều đối tượng
class String {
char *p; public:
String(char *s = "Alibaba") {p = strdup(s);} String(const String &s) {p = strdup(s.p);} ~String() {delete [] p;}
// };
class Diem {
double x,y; public:
Diem(double xx, double yy):x(xx),y(yy){}; Diem():x(0),y(0){};
(107)Cấp huỷ nhiều đối tượng Cấp huỷ nhiều đối tượng
Khi phần tử cấp khởi động với
cùng giá trị
int *pai = new int[10]; Diem *pad = new Diem[5];
// ca diem co cung toa (0,0) String *pas = new String[5];
// Ca chuoi cung duoc khoi dong bang “Alibaba”
Việc huỷ nhiều đối tượng thực cách dùng
// Ca chuoi cung duoc khoi dong bang “Alibaba” Việc huỷ nhiều đối tượng thực cách dùng
delete có thêm dấu [] trước
(108)2.4 Giao diện chi tiết cài đặt 2.4 Giao diện chi tiết cài đặt
Lớp có hai phần tách rời, phần giao diện khai báo
trong phần public để người sử dụng “thấy” sử dụng, hai chi tiết cài đặt bao gồm liệu khai báo
phần private lớp chi tiết mã hoá hàm thành phần, vơ hình người dùng
Ta thay đổi uyển chuyển chi tiết cài đặt, nghĩa
có thể thay đổi tổ chức liệu lớp, có thể thay đổi tổ chức liệu lớp, thay đổi chi tiết thực hàm thành phần (do thay đổi tổ chức liệu để cải tiến giải thuật) Nhưng bảo đảm không thay đổi phần giao diện khơng ảnh hưởng đến người sử dụng, khơng làm đổ vỡ kiến trúc hệ thống
Lớp ThoiDiem cài đặt với thành phần
(109)Lớp ThoiDiem – Cách 1 Lớp ThoiDiem – Cách 1
class ThoiDiem {
int gio, phut, giay;
static bool HopLe(int g, int p, int gy); public:
ThoiDiem(int g = 0, int p = 0, int gy = 0) {Set(g,p,gy);}
(110)Lớp ThoiDiem – Cách 2 Lớp ThoiDiem – Cách 2
class ThoiDiem {
long tsgiay;
static bool HopLe(int g, int p, int gy); public:
ThoiDiem(int g = 0, int p = 0, int gy = 0) {Set(g,p,gy);}
void Set(int g, int p, int gy); void Set(int g, int p, int gy);
int LayGio() const {return tsgiay / 3600;}
int LayPhut() const {return (tsgiay%3600)/60;} int LayGiay() const {return tsgiay % 60;}
void Nhap();
(111)Giao diện chi tiết cài đặt Giao diện chi tiết cài đặt
Có thể xem chi tiết đầy đủ lớp thời điểm cài đặt
giờ, phút, giây cài đặt tổng số giây tập tin nguồn thgian.cpp thgian2.cpp,
Tương tự lớp Stack cài đặt dạng mảng
(112)2.5 Các nguyên tắc xây dựng lớp 2.5 Các nguyên tắc xây dựng lớp
Khi ta nghĩ đến “nó” khái niệm riêng rẽ,
xây dựng lớp biểu diễn khái niệm Ví dụ lớp SinhVien
Khi ta nghĩ đến “nó” thực thể riêng rẽ, tạo đối
tượng thuộc lớp Ví dụ đối tượng Sinh viên “Nguyen Van A” (và thuộc tính khác mã số, năm sinh…)
Lớp biểu diễn cụ thể khái niệm, lớp Lớp biểu diễn cụ thể khái niệm, lớp
ln ln DANH TỪ
Các thuộc tính lớp thành phần liệu, nên
chúng luôn DANH TỪ
Các hàm thành phần thao tác rõ hoạt động
của lớp nên hàm ĐỘNG TỪ
(113)Các nguyên tắc xây dựng lớp Các nguyên tắc xây dựng lớp
// SAI class TamGiac { // DUNG class TamGiac {
Các thuộc tính suy diễn từ thuộc tính khác dùng hàm thành phần để thực tính tốn Chu vi, diện tích tam giác thuộc tính suy diễn
{
Diem A,B,C;
(114)Các nguyên tắc xây dựng lớp Các nguyên tắc xây dựng lớp
Cá biệt có số thuộc tính suy diễn địi hỏi
nhiều tài ngun thời gian để thực tính tốn, ta khai báo liệu thành phần Ví dụ tuổi trung bình dân Việt Nam
class QuocGia {
long DanSo;
double DienTich; double DienTich;
double TuoiTrungBinh; //
public:
double TinhTuoiTB() const; //
(115)Các nguyên tắc xây dựng lớp Các nguyên tắc xây dựng lớp
Chi tiết cài đặt, bao gồm liệu phần mã hố
hàm thành phần thay đổi uyển chuyển phần giao diện, nghĩa phần khai báo hàm thành phần cần phải cố định để không ảnh hưởng đến người sử dụng (xem phần 2.4) Tuy nhiên nên cố gắng cài đặt liệu cách tự nhiên theo khái niệm
// NEN // KHONG NEN
// NEN
class PhanSo {
int tu, mau; public:
// KHONG NEN class PhanSo {
(116)Các nguyên tắc xây dựng lớp Các nguyên tắc xây dựng lớp
Dữ liệu thành phần nên kết hợp thay phân rã
// NEN
class TamGiac {
Diem A,B,C; public:
// KHONG NEN class TamGiac {
double xA, yA,
xB, yB, xC, public: // }; class HinhTron { Diem Tam; double BanKinh; public:
xB, yB, xC, yC; public: // }; class HinhTron {
(117)Các nguyên tắc xây dựng lớp Các nguyên tắc xây dựng lớp
Chi tiết cài đặt, bao gồm liệu phần mã hố
hàm thành phần thay đổi uyển chuyển phần giao diện, nghĩa phần khai báo hàm thành phần cần phải cố định để không ảnh hưởng đến người sử dụng (xem phần 2.4)
Dữ liệu thành phần nên kết hợp thay phân rã
// NEN // KHONG NEN
// NEN
class TamGiac {
Diem A,B,C; public:
//
// KHONG NEN class TamGiac {
double xA, yA,
(118)Các nguyên tắc xây dựng lớp Các nguyên tắc xây dựng lớp
Trong trường hợp, cần có phương thức thiết lập để
khởi động đối tượng
Nên có phương thức thiết lập có khả tự khởi động
không cần tham số
Nếu đối tượng có nhu cầu cấp phát tài ngun phải
có phương thức thiết lập, phương thức thiết lập chép để khởi động đối tượng đối tượng kiểu có để khởi động đối tượng đối tượng kiểu có phương thức huỷ bỏ để dọn dẹp Ngồi cịn phải có phép gán (chương tiếp theo)
Ngược lại, đối tượng đơn giản không cần tài nguyên