1. Trang chủ
  2. » Giáo Dục - Đào Tạo

hoa cuong có thì sử dụng – thích thì lao vào

28 4 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

khai baùo maûng, moãi ñoái töôïng trong maûng phaûi coù khaû naêng töï khôûi ñoäng, nghóa laø coù theå ñöôïc thieát laäp khoâng caàn tham soá.  Ñoái töôïng coù khaû naêng töï khôûi ñoä[r]

(1)

Chương 2 Lớp 2.1 Mở đầu

Một kiểu liệu biểu diễn cụ thể khái niệm thực tế Ví dụ kiểu int biểu diễn cụ thể khái niệm số nguyên toán học

 Trong C++, kiểu liệu nội (built-in data types) :int, long, float, double, char

cho phép kiểm tra lúc biên dịch phát sinh mã chương trình tối ưu Các kiểu liệu cung cấp giao diện tự nhiên độc lập với phần cài đặt

 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

2.2 Lớp thành phần lớp

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; struct Stack

{

Item *st, *top; int size;

};

void StackInit(Stack *ps, int sz) {

ps->st = ps->top = new Item[ps->size=sz]; }

void StackCleanUp(Stack *ps) {

delete [] ps->st; }

bool StackFull(Stack *ps) {

return (ps->top - ps->st >= ps->size); }

(2)

return (ps->top <= ps->st); }

bool StackPush(Stack *ps, Item x) {

if (StackFull(ps)) return false; *ps->top++ = x;

return true; }

bool StackPop(Stack *ps, Item *px) {

if (StackEmpty(ps)) return false; *px = * ps->top;

return true; }

void XuatHe16(long n) {

static char hTab[] =

{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E' ,'F'};

Stack s;

StackInit(&s,8); int x;

do {

StackPush(&s, n%16); n /= 16;

} while(n);

while(StackPop(&s,&x)) cout << hTab[x];

StackCleanUp(&s); }

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 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 sự, dọn dẹp

2 Cách tiếp cận dùng hàm thành phần: //

struct Stack {

(3)

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);}

bool Push(Item x); bool Pop(Item *px); };

bool Stack::Push(Item x) {

if (Full()) return false; *top++ = x;

return true; }

bool Stack::Pop(Item *px) {

if (Empty()) return false; *px = * top;

return true; }

void XuatHe16(long n) {

static char hTab[] =

{'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F'};

Stack s; s.Init(8); int x; {

s.Push(n%16); n /= 16;

} while(n);

while(s.Pop(&x)) cout << hTab[x]; s.CleanUp();

}

Nhaän xeù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 caá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ể đối tượng đóng vai trị trọng tâm Đối tượng thực thao tác

(4)

Các hàm thành phần.

 Là hàm khai báo lớp

 Hàm thành phần định nghĩa bên bên ngồi 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ả veà

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++)

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á class

 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 toàn liệu class Stack

{

Item *st, *top; 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);}

bool Push(Item x); bool Pop(Item *px); };

 Phaùt bieåu:

s.size = 100; // Bao sai

Sẽ bị báo sai lúc biên dịch, nhờ tránh lỗi run-time khó tìm thực chương trình

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

o Thuộc tính private o Thuộc tính public

 Các thành phần nội lớp, bao gồm liệu hàm phục vụ nội

(5)

Ví dụ lớp thuộc tính truy xuất

// Stack.h

typedef int bool; typedef int Item;

const bool false = 0, true = 1; 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() {delete [] st;}

bool Full() const {return (top - st >= size);} bool Empty() const {return (top <= st);}

bool Push(Item x); bool Pop(Item *px); };

// Stack.cpp

#include "stack.h"

bool Stack::Push(Item x) {

if (Full()) return false; *top++ = x;

return true; }

bool Stack::Pop(Item *px) {

if (Empty()) return false; *px = * top;

return true; }

Ví dụ lớp thuộc tính truy xuất

// he16.cpp

#include "stack.h" void XuatHe16(long n) {

static char hTab[] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'};

Stack s(8); int x;

do {

(6)

} while(n);

while(s.Pop(&x)) cout << hTab[x]; }

Tự tham chiếu

 Là tham số ngầm định hàm thành phần trỏ đến đối tượng, có tên this 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 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

Phương thức thiết lập hủy bỏ

Phương thức thiết lập

 Phương thức thiết lập 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 độ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 biệt với hàm thành phần

khác

 Có thể có nhiều phiên khác phương thức thiết lập

typedef int bool; typedef int Item;

const bool false = 0, true = 1; 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() {delete [] st;}

bool Full() const {return (top - st >= size);} bool Empty() const {return (top <= st);}

bool Push(Item x); bool Pop(Item *px); };

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 phép truy xuất

(7)

 Ta làm hàm trở thành hàm bạn lớp cách đưa khai báo hàm vào

trong 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 toàn cục có liên quan mật

thiết với lớp, hàm thành phần lớp khác

Ví dụ: Nhân ma trận, không dùng hàm bạn

const int N = 4; class Vector {

double a[N]; public:

double Get(int i) const {return a[i];} void Set(int i, double x) {a[i] = x;} };

class Matrix {

double a[N][N]; public:

double Get(int i, int j) const {return a[i][j];} void Set(int i, int j, double x) {a[i][j] = x;} //

};

Vector Multiply(const Matrix &m, const Vector &v) {

Vector r;

for (int i = 0; i < N; i++) {

r.Set(i, 0);

for (int j = 0; j < N; j++)

r.Set(i, r.Get(i)+ m.Get(i,j)*v.Get(j)); }

return r; }

Ví dụ minh hoạ: Sử dụng hàm bạn

const int N = 4; class Matrix; class Vector {

double a[N]; public:

double Get(int i) const {return a[i];} void Set(int i, double x) {a[i] = x;}

friend Vector Multiply(const Matrix &m, const Vector &v); };

class Matrix {

(8)

double Get(int i, int j) const {return a[i][j];} void Set(int i, int j, double x) {a[i][j] = x;}

friend Vector Multiply(const Matrix &m, const Vector &v); };

Ví dụ minh hoạ: Sử dụng hàm bạn

Vector Multiply(const Matrix &m, const Vector &v) {

Vector r;

for (int i = 0; i < N; i++) {

r.a[i] = 0;

for (int j = 0; j < N; j++)

r.a[i] += m.a[i][j]*v.a[j]; }

return r; }

Hàm thành phần (const member functions)

 Hàm thành phần hàm thành phần áp dụng cho đối tượng

haèng

 Ta qui định hàm thành phần cách thêm từ khoá const vào cuối khai

báo

 Ta khai báo hàm thành phần không thay đổi thành phần liệu

của đối tượng

extern char *strdup(const char *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;}

void ToLower() {strlwr(p);} };

inline char *strdup(const char *s) {

return strcpy(new char[strlen(s) + 1], s); }

void main() {

const string Truong("Dai Hoc Ban Cong Ton Duc Thang"); string s("ABCdef");

(9)

Truong.Output();

Truong.ToLower(); // Bao loi }

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 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ó giá trị trả cho biết việc tạo

đối tượng có thành cơng theo nghĩa luận lý hay khơng

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:

static bool LeapYear(int y) {return y%400 == || y%4==0 && y%100 != 0;}

static int DayOfMonth(int m, int y);

static bool ValidDate(int d, int m, int y); void Input();

};

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]; }

bool betw(int x, int a, int b) {

return x >= a && x <= b; }

bool CDate::ValidDate(int d, int m, int y) {

(10)

}

void CDate::Input() {

int d,m,y;

cin >> d >> m >> y;

while (!ValidDate(d,m,y)) {

cout << "Please enter a valid date: "; cin >> d >> m >> y;

}

day = d; month = m; year = y; }

Ví dụ thành phần tónh: Stack

// stack.h

typedef int Item; class Stack

{

Item *st, *top; int size;

void Init(int sz) {st = top = new Item[size=sz];} void CleanUp() {if (st) delete [] st;}

public:

Stack(int sz = 20) {Init(sz);} ~Stack() {CleanUp();}

static Stack *Create(int sz);

bool Full() const {return (top - st >= size);} bool Empty() const {return (top <= st);}

bool Push(Item x); bool Pop(Item *px); };

// Stack.cpp

#include <iostream.h> #include "stack.h"

bool Stack::Push(Item x) {

if (Full()) return false; *top++ = x;

return true; }

bool Stack::Pop(Item *px) {

if (Empty()) return false; *px = * top;

return true; }

(11)

{

Stack *ps = new Stack(sz); if (!ps->st)

{

delete ps; return NULL; }

return ps; }

void main() {

Stack *ps = new Stack(50000); // khong biet tao duoc stack khong

Stack *pr = Stack::Create(50000); if (!pr)

{ cout << "Khong the tao stack"; return; } else

pr->Push(5); // }

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 tạo ra.  Khi phương thức huỷ bỏ gọi? Khi đối tượng bị huỷ đi.

 Thời gian từ đối tượng tạo đến bị huỷ gọi thời gian

soáng.

 Vậy vấn đề xác định phương thức thiết lập huỷ bỏ gọi trở thành: Khi đối tượng tạo ?

Khi đối tượng bị huỷ ?

 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

 Ta xét loại sau:

Đối tượng tự động Đối tượng toàn cục Đối tượng tĩnh

Đối tượng cấp phát động Đối tượng thành phần

Đố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

(12)

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

 Khi khởi động đối tượng đối tượng kiểu, chế tạo đối tượng mặc

nhiên chép bit, đối tượng khởi động chia sẻ tài nguyên với đối tượng nguồn

Đối tượng biến địa phương

#include <iostream.h> #include <string.h>

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;}

void Output() const {cout << p;} };

char *strdup(const char *s) {

return strcpy(new char[strlen(s) + 1], s); }

void main() {

string a("Nguyen Van A"); string b = a; // String b(a) a.Output(); cout << "\n"; b.Output(); cout << "\n"; }

 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 chung phần tài nguyên (con

trỏ đến chuỗi “Nguyen Van A”) Khi kết thúc hàm main() hai đối tượng bị huỷ, phần tài nguyên chung bị huỷ lần (SAI)

Đố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 {

(13)

public:

String(char *s = "") {p = strdup(s);}

~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;}

void Output() const {cout << p;} bool Compare(String s) const; };

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);

cout << (c > ? "a > b" : c == ? "a = b" : "a < b") << "\n";

}

 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

delete 0x0f34 delete 0x0f22

Đố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;}

void Output() const {cout << p;} bool Compare(String s) const; String UpCase() const;

};

String String::UpCase() const {

String r = *this; strupr(r.p);

(14)

void main() {

clrscr();

String a("Nguyen Van A");

cout << "a = "; a.Output(); cout << "\n"; String A;

A = a.UpCase();

cout << "a = "; a.Output(); cout << "\n"; cout << "A = "; a.Output(); cout << "\n"; }

Đố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

Đối tượng giá trị trả biểu thức trả Do có chia sẻ tài nguyên (SAI)

 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

và gán phát biểu khởi động: String A = a.UpCase(); 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"; }

 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

Null pointer assignment

(15)

 Các lỗi sai nêu gây chép đối tượng, ta 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 có tham số đối tượng

kiểu, dùng để chép đối tượng

 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 tượng 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);}

~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;}

void Output() const {cout << p;} bool Compare(String s) const; String UpCase() const;

};

char *strdup(const char *s) {

return strcpy(new char[strlen(s)+1], s); }

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; strupr(r.p);

return r; }

void main() {

clrscr();

String a("Nguyen Van A"); String b("Le Van Beo"); String aa = a;

int c = a.Compare(b);

(16)

cout << "a = "; a.Output(); cout << "\n"; String A = a.UpCase();

cout << "a = "; a.Output(); cout << "\n"; cout << "A = "; A.Output(); cout << "\n"; }

 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 delete 0x0d96 delete 0x0d72 delete 0x0d62 delete 0x0d50

 Mỗi đối tượng có tài ngun riêng nên khơng xảy trường hợp vùng tài

nguyên bị giải phóng nhiều laàn

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 chiếu

 Phương thức thiết lập chép dùng để chép nơng, tài nguyên

được chia sẻ có biến đếm để kiểm soát Lưu ý:

 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

cheùp

 Khi truyền tham số đối tượng thuộc lớp có phương thức thiết lập chép, ta nên

truyền tham chiếu có thêm từ khố const

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 ngun

riêng sao chép sâu

 Ta sao chép nơng cách chia sẻ tài nguyên 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 khỏi đối tượng dùng

chung tài nguyên, nói cách khác, phải có tài nguyên riêng (như chép sâu)

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;}

(17)

char *strdup(const char *s) {

return strcpy(new char[strlen(s)+1], s); }

class String {

StringRep *rep; public:

String(const char *s = "") {rep = new StringRep(s);} String(const String &s) {rep = s.rep; rep->n++;} ~String();

void Output() const {cout << rep->p;} bool Compare(String s) const;

String UpCase() const; void ToUpper();

};

String::~String() {

if ( rep->n <= 0) delete rep; }

bool String::Compare(String s) const {

return strcmp(rep->p,s.rep->p); }

String String::UpCase() const {

String r(rep->p); strupr(r.rep->p); return r;

}

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();

(18)

 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 delete 0x0d72 delete 0x0d58 delete 0x0d84 a > b

a = Nguyen Van A delete 0x0d84 a = Nguyen Van A A = NGUYEN VAN A delete 0x0d96 delete 0x0d72 delete 0x0d62 delete 0x0d50 a > b

a = Nguyen Van A a = Nguyen Van A A = NGUYEN VAN A delete 0x0d8a delete 0x0d72 delete 0x0d58

Đố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 (tồ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ỷ

đi kết thúc chương trình

 Đối tượng tĩnh địa phương tạo chương trình thực đoạn mã chứa định

nghĩa đối tượng lần bị huỷ kết thúc chương trì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

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"; }

(19)

Hello, world

And then exitting…

Yêu cầu khơng thay đổi hàm main() hình thức

 Đoạn chương trình sửa lại sau:

#include <iostream.h> void main()

{

cout << "Hello, world.\n"; }

class Dummy {

public:

Dummy() {cout << "Entering a C++ program saying \n";} ~Dummy() {cout << "And then exitting ";}

};

Đối tượng thành phần lớp

 Đối tượng thành phần đối tượng khác, đối tượng thuộc lớp “lớn”

được 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ố thiết lập đối tượng kết

hợp (đối tượng lớn) phải có phương thức thiết lập để cung cấp tham số thiết lập cho đối tượng thành phần

 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 phần bị huỷ đi,

nghĩa phương thức huỷ bỏ gọi cho đối tượng thành phần, sau phương thức huỷ bỏ đối tượng kết hợp gọi

class Diem {

double x,y; public:

Diem(double xx, double yy {x = xx; y = yy;} //

};

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;

(20)

Đối tượng thành phần lớp

class TamGiac {

Diem A,B,C; public:

void Ve() const; //

};

class SinhVien {

String MaSo; String HoTen; int NamSinh; public:

};

TamGiac t; // Bao sai SinhVien s; // Bao sai

Đối tượng thành phần lớp - thiết lập

class Diem {

double x,y; public:

Diem(double xx, double yy {x = xx; y = yy;} //

};

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;

// };

Khởi động đối tượng thành phần: Dùng dấu hai chấm (:)

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; //

};

TamGiac t(100,100,200,400,300,300);

Khởi động đối tượng thành phần: Dùng dấu hai chấm (:)

(21)

String MaSo; String HoTen; int NamSinh; public:

SinhVien(char *ht, char *ms, int ns):HoTen(ht), MaSo(ms) {NamSinh = ns;}

// };

SinhVien s(“Nguyen Van Beo”, “19920005”, 1985); //Ok

Khởi động đối tượng thành phần: Dùng dấu hai chấm (:)

 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:

SinhVien(char *ht, char *ms, int ns):HoTen(ht), MaSo(ms), NamSinh(ns){}

// };

Đố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 bị huỷ bỏ

class SinhVien {

String MaSo, HoTen; int NamSinh;

int SoMon; double *Diem; 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)

{

memcpy(Diem = new double[SoMon], d, SoMon*sizeof(double)); }

Đối tượng thành phần mảng

 Khi mảng tạo ra, phần tử tạo ra, phương thức

(22)

 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ố

 Đố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

– Lớp có phương thức thiết lập khơng tham số

– Lớp có phương thức thiết lập mà tham số có giá trị 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 {

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:

SinhVien(char *ht, char *ms, int ns):HoTen(ht), MaSo(ms), NamSinh(ns){}

// };

String as[3]; // Bao sai Diem ad[5]; // Bao sai

SinhVien asv[7]; // Bao sai

Dùng 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;} //

(23)

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:

SinhVien(char *ht = “Nguyen Van A”, char *ms = “19920014”, int ns = 1982):HoTen(ht), MaSo(ms), NamSinh(ns){}

// };

String as[3]; // Ok: Ca ba phan tu deu la chuoi rong Diem ad[5]; // Ok: ca diem deu la (0,0)

SinhVien asv[7]; // Ok: Het sai ca sinh vien deu co cung hoten, maso, namsinh

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(“”);}

~String() {cout << "delete "<< (void *)p << "\n"; delete [] p;}

// };

class SinhVien {

(24)

SinhVien(char *ht, char *ms, int ns):HoTen(ht), MaSo(ms), NamSinh(ns){}

SinhVien():HoTen(“Nguyen Van A”), MaSo(“19920014”), NamSinh(1982){}

// };

String as[3]; // Ca ba phan tu deu la chuoi rong Diem ad[5]; // ca diem deu la (0,0)

SinhVien asv[7];// Ca sinh vien deu co cung hoten, maso, namsinh

Đối tượng cấp phát động

 Đối tượng cấp phát động đối tượng tạo 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 để huỷ đối tượng  Dùng new delete cấp nhiều đối tượng huỷ nhiều đối 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:

Diem(double xx, double yy):x(xx),y(yy){}; //

}; //

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"); //

delete pa; delete pd; delete pj; delete pi;

(25)

 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:

Cannot find default constructor to initialize array element of type 'Diem' Cannot find default constructor to initialize array element of type String’

 Lỗi khắc phục cách cung cấp phương thức thiết lập để đối tượng có

khả tự khởi độ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){};

// };

 Khi phần tử cấp khởi động với 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 delete có thêm dấu []

trước

delete [] pas; delete [] pad; delete [] pai;

 (?) Có thể thay ba phát biểu phát biểu sau không ? delete pas,pad,pai; // ??

(26)

 Lớp có hai phần tách rời, phần giao diện khai báo 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ã hố 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 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 liệu giờ, phút, giây

tổng số giây tính từ

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);} void Set(int g, int p, int gy);

int LayGio() const {return gio;} int LayPhut() const {return phut;} int LayGiay() const {return giay;} void Nhap();

void Xuat() const; void Tang();

void Giam(); };

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);

int LayGio() const {return tsgiay / 3600;} int LayPhut() const {return (tsgiay%3600)/60;} int LayGiay() const {return tsgiay % 60;}

void Nhap();

void Xuat() const; void Tang();

void Giam(); };

 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 dạng danh sách liên

keát

(27)

 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 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 lớp nên hàm

ĐỘNG TỪ

 Các thuộc tính liệu phải vừa đủ để mô tả khái niệm, không dư, không thiếu

// SAI

class TamGiac {

Diem A,B,C;

double ChuVi, DienTich; public:

// };

// DUNG

class TamGiac {

Diem A,B,C; public:

//

double ChuVi()const; double DienTich() const; };

Cá biệt có số thuộc tính suy diễn đòi hỏi nhiều tài nguyên 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 TuoiTrungBinh; //

public:

double TinhTuoiTB() const; //

};

 Chi tiết cài đặt, bao gồm liệu phần mã hố hàm thành phần thay đổi

(28)

 Dữ liệu thành phần nên kết hợp thay phân rã

 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ã

 Trong trường hợp, nê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ó 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 ngun riêng khơng cần phương thức

thiết lập chép không cần phương thức huỷ bỏ

2.6 Một số ví dụ lớp

 Lớp Diem biểu diễn khái niệm điểm mặt phẳng với hai thành phần toạ độ x

y Khai báo lớp Diem đặt tập tin diem.h chi tiết cài đặt hàm thành phần đặt tập tin diem.cpp Có thể xây dựng số ứng dụng lớp điểm tập tin tdiem.cpp dongho.cpp với ứng dụng tương ứng tdiem.exe dongho.exe

(hoặc dongho2.exe, dongho3.exe)

 Lớp DaGiac biểu diễn khái niệm đa giác mặt phẳng có thao tác tịnh tiến, vị

tự, quay, vẽ… Phần khai báo đặt tập tin dagiac.h, phần cài đặt tập tin

Ngày đăng: 27/04/2021, 18:34

Xem thêm:

w