Professional Documents
Culture Documents
1
MÔN LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
Chương 1
2
Phương pháp phân tích từ-trên-xuống (tt)
chia thành nhiều công Công việc cần
việc nhỏ hơn, đơn giản để giải quyết (A)
giải quyết hơn.
Công việc Công việc Công việc Công việc Công việc Công việc
A11 A12 A1n An1 An2 Ann
3
Cấu trúc 1 chương trình hướng cấu trúc
local data
of function
4
Cấu trúc 1 chương trình hướng cấu trúc
Xét Turbo Pascal, 1 ứng dụng gồm 1 module chương trình và
nhiều module dịch vụ được gọi là Unit. Để sử dụng các thành phần
trong 1 module nào đó, ta phải dùng lệnh Use.
Xét C, 1 ứng dụng gồm nhiều module ngang hàng, mỗi module là
1 file gồm nhiều hàm chức năng. Điểm nhập ứng dụng là hàm
main(). Module C cũng có thể là file thư viện liên kết tĩnh (*.lib) hay
động (*.dll). Để sử dụng các thành phần trong 1 module nào đó, ta
phải dùng lệnh #include.
5
Hai module sử dụng tài nguyên của nhau
//đặc tả interface của module A //đặc tả interface của module B
#define _AH #define _BH
#ifndef _BH #ifndef _AH
#include B.h #include A.h
#endif #endif
extern int A_intA; extern int B_intA;
typedef struct {...} A_Type1; typedef struct {...} B_Type1;
#define A_PI 3.14159 #define B_PI 3.14159
int A_func1(int a, double b); int B_func1(char c, char* d);
Chương 2
6
Nội dung
2.1 Cấu trúc của 1 ứng dụng hướng đối tượng
2.2 Đối tượng, thuộc tính, tác vụ.
2.3 Abstract type và class.
2.4 Tính bao đóng.
2.5 Tính thừa kế & cơ chế 'override'.
2.6 Tính bao gộp.
2.7 Thông điệp, tính đa xạ và kiểm tra kiểu.
2.8 Tính tổng quát hóa.
2.9 Tính thường trú.
Đối tượng
(object)
local data
entry of object
local data
of operation
7
Cấu trúc chương trình OOP
Cấu trúc chương trình hướng đối tượng rất thuần nhất, chỉ chứa
1 loại thành phần : đối tượng.
Các đối tượng có tính độc lập rất cao ⇒ quản lý, kiểm soát
chương trình rất dễ (cho dù chương trình có thể rất lớn) ⇒ dễ
nâng cấp, bảo trì.
Không thể tạo ra dữ liệu toàn cục của chương trình ⇒ điểm yếu
nhất của chương trình cấu trúc không tồn tại nữa.
Implementation
(class)
Interface
(abstract type)
8
Kiểu trừu tượng (Abstract type)
Abstract type (type) định nghĩa interface sử dụng đối tượng. Ta
dùng tên nhận dạng để đặt tên cho kiểu và để nhận dạng nó.
Interface là tập hợp các 'entry' mà bên ngoài có thể giao tiếp với
đối tượng.
Ta dùng signature để định nghĩa mỗi 'entry'. Signature gồm :
tên tác vụ (operation, function)
danh sách tham số hình thức, mỗi tham số được đặc tả bởi 3
thuộc tính : tên, type và chiều di chuyển (IN, OUT, INOUT).
đặc tả chức năng của tác vụ (thường ở dạng chú thích).
Ta dùng tên của abstract type (chứ không phải class) để đặc tả
kiểu cho biến, thuộc tính, tham số hình thức.
User không cần quan tâm đến class (hiện thực cụ thể) của đối
tượng.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 2 : Các khái niệm chính của lập trình hướng đối tượng
Trường ĐH Bách Khoa Tp.HCM Slide 17
9
Class (Implementation)
~ Ta dùng tên nhận dạng để đặt tên cho class và để nhận dạng nó.
Class định nghĩa chi tiết hiện thực đối tượng :
định nghĩa các thuộc tính dữ liệu, mỗi thuộc tính được đặc tả bởi
các thông tin về nó như tên nhận dạng, kiểu dữ liệu, tầm vực truy
xuất,... Kiểu của thuộc tính có thể là type cổ điển (số nguyên, thực,
ký tự, chuỗi ký tự,...) hay 'abstract type', trong trường hợp sau thuộc
tính sẽ là tham khảo đến đối tượng khác. Trạng thái của đối tượng
là tập giá trị tại thời điểm tương ứng của tất cả thuộc tính của đối
tượng. Trong thời gian tồn tại và hoạt động, trạng tái của đối tượng
sẽ thay đổi.
'coding' các tác vụ (miêu tả giải thuật chi tiết về hoạt động của tác
vụ) và các 'internal function'.
~ Định nghĩa các tác vụ tạo (create) và xóa (delete) đối tượng.
~ Định nghĩa các tác vụ 'constructor' và 'destructor'.
~ User không cần quan tâm đến class của đối tượng.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 2 : Các khái niệm chính của lập trình hướng đối tượng
Trường ĐH Bách Khoa Tp.HCM Slide 19
10
Tính bao đóng (encapsulation)
Bao đóng : che dấu mọi chi tiết hiện thực của đối tượng, không
cho bên ngoài thấy và truy xuất ⇒ tạo độ độc lập cao giữa các
đối tượng (hay tính kết dính - cohesion giữa các đối tượng rất
thấp).
che dấu các thuộc tính dữ liệu : nếu cần cho phép bên ngoài
truy xuất 1 thuộc tính, ta tạo 2 tác vụ get/set tương ứng để
giám sát và kiểm soát việc truy xuất (thuộc tính này vẫn được
che giấu).
che dấu chi tiết hiện thực các tác vụ.
che dấu các internal function và sự hiện thực của chúng.
Java, VC++ cung cấp các từ khóa private, protected, public để
xác định tầm vực truy xuất từng thành phần của class.
11
Ví dụ về thừa kế và override — VC++
class Geometry { // abstract base class
public:
Geometry( );
virtual void Draw( Window *pWnd ) = 0; // abstract operation
protected:
int xPos, yPos;
COLORREF color;
};
class Group : public Geometry {
public:
Group( );
~Group( );
virtual void Draw( Window *pWnd ); // override
private:
Geometry **ppGeo; // pointer container
int geoCount;
};
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 2 : Các khái niệm chính của lập trình hướng đối tượng
Trường ĐH Bách Khoa Tp.HCM Slide 23
O1 O2 O2
O1
O3 O3
12
Ví dụ về bao gộp - VC++
class Geometry { // abstract base class
public:
Geometry( );
~Geometry( );
virtual void Draw( Window *pWnd ) = 0; // abstract operation
protected:
int xPos, yPos;
double xScale, yScale;
COLORREF color;
};
13
Tính đa xạ (Polymorphism)
Cùng 1 lệnh gởi thông điệp đến đối tượng thông qua cùng 1 tham
khảo nhưng ở vị trí/thời điểm khác nhau có thể kích hoạt việc thực
thi tác vụ khác nhau của các đối tượng khác nhau.
T1 p1; // C1 và C2 là 2 class Java hiện thực T1
...
p1 = New C1; // tạo đối tượng C1, gán tham khảo vào biến p1
p1.meth1(...); // gởi thông điệp nhờ tác vụ meth1 thực thi
...
p1 = New C2; // tạo đối tượng C2, gán tham khảo vào biến p1
p1.meth1(...); // gởi thông điệp nhờ tác vụ meth1 thực thi
Lệnh gởi thông điệp p1.meth1(...); ở 2 vị trí khác nhau kích hoạt
2 tác vụ khác nhau của 2 class khác nhau.
14
Tính tổng quát hóa (Generalization)
15
Tổng kết
Mô hình hướng đối tượng quan niệm thế giới (hay chương trình) bao
gồm các đối tượng độc lập sống chung và tương tác lẫn nhau.
Các đặc điểm chính của mô hình hướng đối tượng :
Bao đóng : mỗi đối tượng bao gồm 1 số dữ liệu và tác vụ. Các tác
vụ thiết lập nên hành vi của đối tượng. Các đối tượng cùng loại
được đặc tả bằng 1 class.
Các đối tượng độc lập và tương tác lẫn nhau bằng cách gởi thông
điệp.
Giữa các class/đối tượng có thể tồn tại quan hệ bao gộp, thừa kế,
tổng quát hóa.
Tính đa xạ : kết quả của sự kiểm tra kiểu chặt dựa vào mối quan
hệ 'conformity'.
Tính thường trú : mỗi đối tượng tồn tại khi còn ít nhất 1 tham khảo
đến nó.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 2 : Các khái niệm chính của lập trình hướng đối tượng
Trường ĐH Bách Khoa Tp.HCM Slide 31
Chương 3
16
Tổng quát về vấn đề dịch OOP
Chương trình là tập các đối tượng sống độc lập và tương tác lẫn
nhau khi cần thiết.
Các đối tượng thuộc 1 số loại nhất định (n)
Mỗi loại đối tượng được miêu tả bởi 1 type & 1 class
Mã nguồn chương trình là tập n định nghĩa type & class
Dịch chương trình OOP là qui trình lặp dịch n type & n class.
Ta sẽ miêu tả qui trình dịch 1 type và 1 class trong chương này.
Abstract type chỉ chứa thông tin trừu tượng (interface), không
miêu tả sự hiện thực → Kết quả việc dịch 1 type chỉ dừng lại ở
việc xây dựng cây ngữ nghĩa của type tương ứng để phục vụ việc
kiểm tra kiểu của chương trình dịch, chứ không tạo code mã máy.
Chỉ cần 3 bước : duyệt từ vựng, phân tích cú pháp và phân tích
ngữ nghĩa.
Nên dùng công cụ hỗ trợ như LEX, YACC cho 2 bước duyệt từ
vựng & phân tích cú pháp.
17
Dịch 1 class
Dịch class là công việc chính của chương trình dịch hướng đối
tượng.
Gồm 2 công việc chính : dịch thuộc tính dữ liệu và dịch các
method (hay các internal function).
Cần đầy đủ các bước : duyệt từ vựng, phân tích cú pháp, phân
tích ngữ nghĩa và tạo mã.
Nên dùng công cụ hỗ trợ như LEX, YACC cho 2 bước duyệt từ
vựng & phân tích cú pháp.
18
Dịch thuộc tính dữ liệu (tt)
19
Tạo bảng địa chỉ các tác vụ
pvftbl
fname faddr
class C1 : C0 { 0 "proc1" C0_proc1
double d;
int i ; 1 "proc2" C1_proc2
...
public : 2 "proc3" C0_proc3
void proc2(); //override
3 "proc4" C1_proc4
int proc4(int i, double k);
void proc5 (double d); 4 "proc5" C1_proc5
...
}; 5 .... ...
20
Dịch 1 method
int C1_proc1(C1* p, int i, double d) {
int C1::proc1(int i,double k) {
C2 o2; C2 *p2;
C2 o2;
// truy xuất thuộc tính
C2 *p2;
p->C1_i = i; p->C1_d = d;
C1::i = i;
// gọi hàm
d = k;
C1_proc5(p,d);
C1::proc5(d);
C2_proc2(&o2, i,d);
o2.proc2(i,d);
// gởi thông điệp : kiểm tra, load,
p2 = New(C2); 1 // cập nhật bảng địa chỉ method
p2->proc2(i,d);
.... 2 for (i = 0; i <C2METHCNT; i ++)
if (strcmp ("proc2", p2->
};
pvftbl[i].fname)==0) break;
3 (*p2->pvftbl[i].faddr)(p2,i,d);
};
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 3: Cơ chế dịch mã OOP sang mã máy
Trường ĐH Bách Khoa Tp.HCM Slide 41
21
Tối ưu hóa code tạo ra
Có 2 vấn đề lớn trong quá trình dịch 1 class sang ngôn ngữ cổ
điển.
Bảng địa chỉ các method chiếm nhiều không gian.
Tốn thời gian chạy lệnh gởi thông điệp : kiểm tra, tìm, load đối
tượng, cập nhật bảng địa chỉ các tác vụ, tìm chỉ số method
cần gọi và gọi gián tiếp qua địa chỉ trong bảng.
1 số chương trình dịch tìm cách tối ưu hóa các vấn đề trên.
slide sau là các tối ưu hóa của chương trình dịch C++ và các giá
phải trả.
22
Tối ưu hóa code tạo ra (tt)
cái giá phải trả của việc tối ưu hóa trong C++ :
người lập trình phải tự quyết định tác vụ nào cần xử lý theo
cơ chế đa xạ, tác vụ nào không ? Nếu sự quyết định này sai
thì sẽ gây lỗi khi chạy, mà là người thì khó lòng quyết định
chính xác.
tính đa xạ chỉ đúng giữa các đối tượng có mối quan hệ
con/cha, ở đó thứ tự các địa chỉ method của mọi class con
trong bảng địa chỉ luôn giống thứ tự các method tương ứng
của class cha, tuy nhiên giữa 2 class bất kỳ thì không thể
đảm bảo → kiểm tra kiểu trong C++ không thể nâng cấp lên
bằng cách dùng mối quan hệ "conformity".
Chương 4
23
4.1 Ngôn ngữ Visual C++
24
Đa thừa kế
Đa thừa kế trong định nghĩa class, hấp dẫn cho người lập trình nhưng
chi phí hiện thực thì rất cao :
dễ gây ra việc trùng tên giữa các thành phần nằm trong các class cha
khác nhau nhưng đều được thừa kế cho class con ⇒ phải giải quyết
vấn đề trùng tên và tránh nhặp nhằng trong việc truy xuất chúng.
1 class có thể chứa nhiều class cha trùng nhau ⇒ phải giải quyết việc
duplicate các thành phần của các class cha trùng nhau này (dư thừa và
mất tính nhất quán) ⇒ VC++ đề nghị dùng "virtual base class" để tối
ưu hóa bộ nhớ đối tượng. a. b.
Đa thừa kế
Phát biểu :
class NguoiCa : public Nguoi, public Ca {...};
sẽ tạo ra các đối tượng NguoiCa có cấu trúc dữ liệu theo hình a.
trong slide trước ⇒ các thuộc tính trong class Sinhvat được nhân
bản và tồn tại 2 lần ở 2 vị trí khác nhau trong đối tượng NguoiCa
⇒ dư thừa dữ liệu và mất tính nhất quán dữ liệu.
Còn phát biểu :
class NguoiCa : public virtual Nguoi, public virtual Ca {...};
sẽ tạo ra các đối tượng NguoiCa có cấu trúc dữ liệu theo hình b.
trong slide trước ⇒ các thuộc tính trong class Sinhvat chỉ tồn tại
1 lần trong đối tượng NguoiCa ⇒ khắc phục được sự dư thừa dữ
liệu và không mất tính nhất quán dữ liệu.
25
Class trừu tượng (Abstract class)
VC++ hỗ trợ khái niệm "abstract class" để định nghĩa class chỉ chứa thông
tin interface nhưng không cho phép dùng class này để định nghĩa kiễu cho
biến hay thuộc tính (trừ pointer). Một “abstract class” là 1 class chứa ít
nhất 1 "pure virtual funtion“, một "pure virtual funtion“ là 1 virtual function
được gán =0 (nghĩa là không có phần hiện thực kèm theo).
class Geometry { // abstract class
public:
Geometry( );
~Geometry( );
virtual void Draw( Window *pWnd ) = 0; // pure virtual function
protected:
int xPos, yPos;
double xScale, yScale;
COLORREF color;
};
26
Hỗ trợ tính đa xạ có chọn lọc
Định nghĩa 'virtual function' nếu muốn áp dụng tính đa xạ trong lệnh
gởi thông điệp yêu cầu hàm này thực thi.
Tất cả các 'virtual function' của class được quản lý trong 1 danh
sách "virtual function table". Danh sách này là 1 trong các field dữ
liệu nằm trong đối tượng được tạo tự động bởi chương trình dịch.
địa chỉ function 1
địa chỉ function 2
địa chỉ function 3
địa chỉ function 4
địa chỉ function 5
27
Skeleton định nghĩa class
class Geometry : Object { // == class Geometry : public Object {
public:
Geometry( );
~Geometry( );
virtual void Draw( Window *pWnd ); // virtual method
BOOL IsDisplayed(void);
....
protected:
COLORREF color;
....
private :
int xPos, yPos;
double xScale, yScale;
...
};
class Point : Geometry {};
class Line : Geometry { .... };
class Polygon : Geometry {....};
class Rectangle : Geometry {....};
....
InitInstance()
DoModal()
CProgramDlg
CProgramApp
28
Cấu trúc 1 chương trình SDI đơn giản
InitInstance()
CMainFrame
CProgramView CProgramDoc
CSingleDocTemplate
CProgramApp
InitInstance()
CChildFrame
CProgramView CProgramDoc
CMultiDocTemplate
CProgramApp
29
4.2 Ngôn ngữ Java
30
Tạo & xóa đối tượng
Phải gọi hàm tạo đối tượng 1 cách tường minh, nhưng không cần
xóa đối tượng (việc này nên để cho module dọn rác của JVM thực
hiện để đảm bảo tính đúng đắn và an toàn).
class C1 extends RootClass {...}
C1 o1; // o1 chứa tham khảo đến đối tượng C1
o1 = New C1; //tạo đối tượng mới và gán tham khảo vào biến đối
tượng
Việc dùng tên interface đặc tả kiểu cho biến, thuộc tính luôn có lợi
hơn việc dùng tên class. Thí dụ về ứng dụng hiển thị đồng hồ thời
gian thực trong chương này sẽ cho ta thấy rõ điều này.
2. Đơn thừa kế trong định nghĩa interface và định nghĩa class ⇒ mối
quan hệ thừa kế giữa các interface/class khá đơn giản, dễ hiện
thực.
31
Tầm vực truy xuất các thành phần
4. Tầm vực truy xuất các thành phần trong đối tượng :
private : thành phần bị che dấu hoàn toàn.
protected : che dấu bên ngoài nhưng cho phép các đối tượng
con, cháu, chắt... truy xuất.
public : cho phép tất cả mọi nơi truy xuất.
friendly : cho phép mọi phần tử trong cùng package truy xuất.
Đây là tầm vực mặc định và không có từ khóa tầm vực tường
minh.
Hỗ trợ package
5. Package là đơn vị đóng gói các class và cũng là đơn vị quản lý
tầm vực của java, mỗi package chứa nhiều class (ở dạng mã
trung gian — mã bytecode).
package graphics;
public class Circle extends Graphic implements Draggable {
...
}
Tất cả mọi phần tử được định nghĩa trong 1 file mã nguồn đều
thuộc 1 package, tên package này được đặc tả trong phát biểu
package, phát biểu này phải nằm ở đầu file mã nguồn. Nếu
không có thì các class trong file mã nguồn sẽ được chứa trong
package mặc định (không có tên).
Nhiều file source có thể được dịch và lưu trong cùng 1 package.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 4 : Tổng quát về mức độ hỗ trợ OOP của VC++ & Java
Trường ĐH Bách Khoa Tp.HCM Slide 64
32
Hỗ trợ đầy đủ tính đa xạ
7. Các đối tượng chỉ tồn tại tạm thời trong 1 session chạy JVM.
Coe của ứng dụng phải tạo ra đối tượng nếu muốn dùng nó,
nhưng không cần phải xóa đối tượng. Đối tượng sẽ tồn tại 1 khi
còn tham khảo đến nó trong không gian của 1 session JVM.
Module Garbage Collection trong JVM sẽ chịu trách nhiệm phát
hiện đối tượng ‘rác’ và xóa nó ra khỏi bộ nhớ JVM.
8. Có quyền 'override' bất kỳ function nào của class cha. Class cha
có thể quyết định không cho các class con override tác vụ của
mình bằng cách dùng từ khóa final trong lệnh định nghĩa tác vụ
đó.
9. Cho phép định nghĩa các hàm 'overloaded' : cùng tên nhưng
'signature' khác nhau.
33
Thí dụ về chương trình Java
import java.net.*;
public class getnet {
public static void main(String args[]) {
try {
if(args.length!=1) {
System.out.println("Usage: java AddrLookupApp <HostName>");
return;
}
InetAddress host = InetAddress.getByName(args[0]);
String hostName = host.getHostName();
System.out.println ("Host name : "+hostName);
System.out.println ("IP address:"+host.getHostAddress());
}
catch (UnknownHostException e) {...}
}
} Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 4 : Tổng quát về mức độ hỗ trợ OOP của VC++ & Java
Trường ĐH Bách Khoa Tp.HCM Slide 67
GUIClock
<<chứa>> AlarmClock
12.34.25
wakeup()
34
Thí dụ về các class Java
35
Thí dụ về các class Java
private synchronized int findNextSlot() {
for (int i = 0; i < MAX_CAPACITY; i++) {
if (sleepFor[i] == UNUSED)
return i;
}
return NOROOM;
}
private synchronized void wakeUpSleeper(int sleeperIndex) {
sleepers[sleeperIndex].wakeUp();
sleepers[sleeperIndex] = null;
sleepFor[sleeperIndex] = UNUSED;
}
//còn tiếp ở slide kế
36
Thí dụ về các class Java
public interface Sleeper {
public void wakeUp();
public long ONE_SECOND = 1000;// in milliseconds
public long ONE_MINUTE = 60000; // in milliseconds
}
import java.applet.Applet;
import java.awt.Graphics;
import java.util.*;
import java.text.DateFormat;
public class GUIClock extends Applet implements Sleeper {
private AlarmClock clock;
public void init() {
clock = new AlarmClock();
}
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 4 : Tổng quát về mức độ hỗ trợ OOP của VC++ & Java
Trường ĐH Bách Khoa Tp.HCM Slide 73
37
MÔN KỸ THUẬT LẬP TRÌNH
Chương 5
38
MÔN KỸ THUẬT LẬP TRÌNH
Chương 6
39
MÔN KỸ THUẬT LẬP TRÌNH
Chương 7
40
Tổng quát về gọi hàm trong VC++
Trong thân của 1 tác vụ, xét lệnh sau :
::function1(...);
Lệnh trên là lời gọi hàm cổ điển function1(). Hàm function1() phải
tồn tại trong module nào đó của phần mềm hoặc trong module thư
viện mà phần mềm sẽ liên kết đến.
Trong thân của 1 tác vụ, xét lệnh sau :
function1(...);
Nếu function1() không được định nghĩa trong class của đối tượng
tương ứng thì lệnh trên là lời gọi hàm cổ điển function1(). Hàm
function1() phải tồn tại trong module nào đó của phần mềm hoặc
trong module thư viện mà phần mềm sẽ liên kết đến.
Biến obj miêu tả bản thân đối tượng MyClass (1 cách tường
minh, xác định và không nhầm lẫn với bất kỳ đối tượng thuộc
class nào khác. Cú pháp gọi tác vụ thông qua biến đối tượng là :
obj.function1(...);
lệnh trên luôn được dịch ra thành lời gọi hàm function1(...) của
class MyClass tại thời điểm dịch. Do đó tại thời điểm chạy, nếu
biến obj đang chứa 1 đối tượng khác thì lệnh obj.function1(..) vẫn
luôn là lời gọi hàm function1(..) của class MyClass. Không có đa
xạ trong trường hợp này. Ngữ nghĩa của lời gọi hàm như trên có
thể đúng/không đúng với yêu cầu của người lập trình tại từng thời
điểm/vị trí chạy nó.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 7 : Gọi hàm, gởi thông điệp & đa xạ trong VC++
Trường ĐH Bách Khoa Tp.HCM Slide 82
41
Tổng quát về gọi hàm trong VC++
Trong thân của 1 tác vụ, xét lệnh sau :
function1(...);
Nếu function1() được định nghĩa trong class của đối tượng tương
ứng thì lệnh trên sẽ được chuyển thành lệnh :
this->function1(...);
trong đó this là tên biến tham khảo đến đối tượng hiện hành.
Lệnh this->function1(...); là trường hợp đặc biệt của lệnh :
pobj->function1(...);
trong đó pobj là tên biến tham khảo đến đối tượng nào đó đã được
định nghĩa trước đó.
Bây giờ chúng ta hãy khảo sát chi tiết về việc xử lý lệnh
pobj->function1(...); trong VC++.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 7 : Gọi hàm, gởi thông điệp & đa xạ trong VC++
Trường ĐH Bách Khoa Tp.HCM Slide 83
42
Thí dụ củng cố nội dung chương 7
Giới thiệu bài thực hành số 8.
Chương 8
43
Tổng quát về gởi thông điệp trong Java
Trong Java, chỉ có 1 cách truy xuất đối tượng duy nhất : thông qua
biến tham khảo đến đối tượng. Biến tham khảo được định nghĩa
theo 1 trong 2 cách :
MyClass pobj; //dùng class miêu tả kiểu cho biến
MyInterface pobj; //dùng interface miêu tả kiểu cho biến
Trong Java, các lệnh thực thi đều phải nằm trong thân của 1 tác vụ
nào đó của 1 class nào đó.
44
Xử lý lệnh gởi thông điệp trong Java
Giả sử biến tham khảo pobj đã được định nghĩa như sau :
MyClass pobj;
Việc xử lý lệnh gởi thông điệp pobj.function1(...); là kiểm tra xem function1
có phải là tác vụ private của class MyClass không?
Nếu function1 là tác vụ private, lệnh gởi thông điệp chỉ được xử lý khi
pobj = this. Máy sẽ dịch ra lời gọi hàm tường minh đến hàm function1
của class FuncClass (class chứa hàm function1), bất chấp tại thời
điểm chạy biến this đang tham khảo đến đối tượng thuộc class nào
khác. Như vậy, cách giải quyết này không tạo ra tính đa xạ cho lời gởi
thông điệp.
Nếu function1 có tầm vực khác private, lệnh gởi thông điệp sẽ được
dịch ra đoạn mã máy thực hiện việc tìm và liên kết động tới hàm
fucntion1 nhờ bảng địa chỉ các tác vụ của đối tượng được tham khảo
bởi biến pobj. Như vậy, cách giải quyết này sẽ tạo ra tính đa xạ cho
lời gởi thông điệp.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 8 : Gọi hàm, gởi thông điệp & đa xạ trong Java
Trường ĐH Bách Khoa Tp.HCM Slide 89
45
MÔN KỸ THUẬT LẬP TRÌNH
Chương 9
46
T nh t ̉ng quat hoa (tt)
Hàm tổng quát hóa (function template) cho phép ta đặc tả 1 tập
các hàm mà dùng chung đoạn lệnh thực thi nhưng tác động trên
những dữ liệu thuộc kiểu hay class khác nhau và/hoặc với số
lượng khác nhau.
Class tổng quát hóa (class template) cho phép ta đặc tả 1 tập
các class có tính chất và giao diện giống nhau nhưng tác động
trên những dữ liệu thuộc kiểu hay class khác nhau và/hoặc với số
lượng khác nhau. Class tổng quát hóa cho phép sản sinh tự động
các class bình thường, các class bình thường tự nó chỉ có thể tạo
ra đối tượng.
Function template
Function template cho phép ta đặc tả 1 tập các hàm mà dùng chung
đoạn lệnh thực thi nhưng tác động trên những dữ liệu thuộc kiểu hay
class khác nhau. Thí dụ hàm IntSwap() sau đây :
void IntSwap(int& a, int& b ) {
int c = a;
a = b; b = c;
}
chỉ cho phép swap 2 số nguyên, nhưng template MySwap() sau :
template <class T> void MySwap( T& a, T& b ) {
T c (a);
a = b; b = c;
}
định nghĩa 1 họ các hàm swap 2 dữ liệu có kiểu bất kỳ.
47
Function template (tt)
Ta có thể gọi hàm “template function” y như gọi hàm bình
thường, không có sự khác biệt nào cả :
int i, j;
char k;
MySwap (i, j); //Ok
MySwap (i, k); //Sai vì khác kiểu.
Class template
Class template cho phép ta đặc tả 1 tập các class mà dùng chung
interface và cấu trúc dữ liệu nhưng tác động trên những dữ liệu thuộc kiểu
hay class khác nhau. Thí dụ class IntStack sau đây :
class IntStack {
int StackBuffer[100];
int cItems;
public:
void IntStack( void ) : cItems( 100 ) {};
void push( const int item );
int pop( void );
}; int IntStack::pop ( void ) {
if ( cItems < 100)
void IntStack::push( const int item ) { return StackBuffer[cItems++];
if ( cItems > 0 ) StackBuffer[--cItems] = item; else
else throw "Stack overflow error."; throw "Stack underflow error.";
return; }
}
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 9 : Tổng quát hóa trong xây dựng hàm & class
Trường ĐH Bách Khoa Tp.HCM Slide 96
48
Class template
Class IntStack được đặc tả ở slide trước chỉ có thể tạo ra các đối
tượng stack chứa các số nguyên. Nếu muốn stack chứa các số thực,
ta phải định nghĩa mới 1 class khác (gần giống với class IntStack).
Tương tự, nếu muốn stack chứa các chuỗi, ta lại phải định nghĩa mới
1 class khác (gần giống với class IntStack)....
Class template cho phép ta khắc phục được phiền hà này.
Class template
Cú pháp khai báo 1 class template :
template-declaration :
template < template-argument-list > declaration
template-argument-list :
template-argument
template-argument-list , template-argument
template-argument :
type-argument
argument-declaration
type-argument :
class identifier
typename identifier
declaration :
là đặc tả class bình thường nhưng có nhiều vị trí có dùng các tham số
template.
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 9 : Tổng quát hóa trong xây dựng hàm & class
Trường ĐH Bách Khoa Tp.HCM Slide 98
49
Class template (tt)
template <class T, int i> class MyStack {
T StackBuffer[i];
int cItems;
public:
void MyStack( void ) : cItems( i ) {};
void push( const T item );
T pop( void );
};
Cho phép đặc tả các class miêu tả các stack gồm nhiều dữ liệu bất kỳ
nào đó, thí dụ :
MyStack<int,20> intstack; // biến quản lý stack có tối đa 20 số nguyên.
MyStack<CString,40> strstack; // biến quản lý stack có tối đa 40 chuỗi.
MyStack<double,100> dblstack; // biến quản lý stack có tối đa 100 số
thực.
50
Class template (tt)
Xem phần phụ lục chương 9 để biết chi tiết, cụ thể của 2 template MFC được
dùng phổ biến nhất là CArray và CList.
51
Định nghĩa class "serializable"
//1. thừa kế class CObject
class MyClass : public CObject {
public :
//3. dùng macro DECLARE_SERIAL
DECLARE_SERIAL( MyClass);
//4. định nghĩa constructor không tham số
MyClass();
virtual void Serialize( CArchive& archive );
...
};
//5. dùng macro IMPLEMENT_SERIAL
IMPLEMENT_SERIAL(MyClass, CObject, 1 )
//2. Override hàm Serialize
void MyClass::Serialize( CArchive& ar ) { ...}
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 9 : Tổng quát hóa trong xây dựng hàm & class
Trường ĐH Bách Khoa Tp.HCM Slide 103
52
Ghi đối tượng
Để ghi 1 đối tượng thuộc class "serializable", ta cần thực hiện 5 tác vụ :
1. Định nghĩa đối tượng CFile miêu tả file chứa thông tin.
2. Định nghĩa đối tượng CArchive ổ chế độ "store".
3. Gọi tác vụ Serialize khi cần ghi đối tượng.
4. Đóng đối tượng CArchive
5. Đóng file
//1. Định nghĩa đối tượng CFile
CFile theFile;
theFile.Open("c:\\persist.bin", CFile::modeCreate | CFile::modeWrite);
//2. Định nghĩa đối tượng CArchive
CArchive archive(&theFile, CArchive::store);
MyClass obj;
//3. Gọi tác vụ Serialize để ghi đối tượng
obj.Serialize(archive);
//4. Gọi tác vụ Close để đóng đối tượng archive
archive.Close();
//5. Gọi tác vụ Close để đóng đối tượng file
theFile.Close();
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 9 : Tổng quát hóa trong xây dựng hàm & class
Trường ĐH Bách Khoa Tp.HCM Slide 105
53
Thí dụ về đọc/ghi đối tượng
intB1 = 2
dblB2 = 2.345
ba
intA1 = 1 intA1 = 3
dblA2 = 1.234 dblA2 = 3.456
pab pab
pba
pba1 intA1 = 4
dblA2 = 4.567
pab
đối tượng class B
đối tượng class A
Môn : Lập trình hướng đối tượng
Khoa Công nghệ Thông tin Chương 9 : Tổng quát hóa trong xây dựng hàm & class
Trường ĐH Bách Khoa Tp.HCM Slide 107
54