1. Trang chủ
  2. » Mẫu Slide

LTHDT_CH02-PhepToan [Compatibility Mode] OTTN

71 1 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

Thông tin cơ bản

Định dạng
Số trang 71
Dung lượng 649,42 KB

Nội dung

döõ lieäu nhaäp cho kieåu döõ lieäu ñang ñònh nghóa, ta ñònh nghóa pheùp toaùn >> nhö haøm toaøn cuïc vôùi tham soá thöù nhaát laø tham chieáu ñeán moät ñoái töôïng thuoäc lôùp[r]

(1)

Chương 2 Chương 2

Định nghĩa phép toán Định nghĩa phép toán

1

(2)

Nội dung

Nội dung

1 Mở đầu

2 Hàm phép toán 3 Chuyển kiểu

4 Gán khởi động

(3)

1 Mở đầu 1 Mở đầu

Trong C++, kiểu liệu nội (built-in data types):

int, long, float, double, char… với phép toán +,-,*,/… cung cấp cài đặt cụ thể khái niệm giới thực Các phép toán cho phép người sử dụng tương tác với chương trình theo giao diện tự nhiên tiện lợi.

Người sử dụng có nhu cầu tạo kiểu liệu

3

Người sử dụng có nhu cầu tạo kiểu liệu

mà ngôn ngữ không cung cấp ma trận, đa thức, số phức, vector

Lớp C++ cung cấp phương tiện để qui định

(4)

Mở đầu Mở đầu

Một phép tốn ký hiệu mà thao tác

liệu, liệu thao tác gọi toán hạng, thân ký hiệu gọi phép toán.

Phép toán có hai tốn hạng gọi phép tốn hai

ngơi (nhị phân), có tốn hạng gọi phép tốn ngơi (đơn phân).

Sau định nghĩa phép toán cho kiểu liệu mới, Sau định nghĩa phép toán cho kiểu liệu mới,

ta sử dụng cách thân thiện Ví dụ: SoPhuc z(1,3), z1(2,3.4), z2(5.1,4);

z = z1 + z2;

(5)

2 Hàm phép toán 2 Hàm phép toán

Bản chất phép tốn ánh xạ, định nghĩa

phép toán định nghĩa hàm Tất phép tốn có trong C++ định nghĩa.

+ - * / % ^ & | ~ !

= < > += -= *= /= %= ^= &= |= << >> <<= >>= == != <= >= &&

|| ++ ->* , -> [] () new delete

5

|| ++ ->* , -> [] () new delete

Ta định nghĩa phép tốn hàm có tên đặc biệt bắt

(6)

Ví dụ minh hoạ – Lớp PhanSo Ví dụ minh hoạ – Lớp PhanSo typedef int bool;

typedef int Item;

const bool false = 0, true = 1; long USCLN(long x, long y)

{

long r;

x = abs(x); y = abs(y); x = abs(x); y = abs(y);

if (x == || y == 0) return 1; while ((r = x % y) != 0)

{

x = y; y = r; }

(7)

Ví dụ minh hoạ – Lớp PhanSo Ví dụ minh hoạ – Lớp PhanSo

class PhanSo {

long tu, mau; void UocLuoc(); public:

PhanSo(long t, long m) {Set(t,m);} void Set(long t, long m);

long LayTu() const {return tu;} long LayMau() const {return mau;}

7

long LayMau() const {return mau;} PhanSo Cong(PhanSo b) const;

PhanSo operator + (PhanSo b) const;

PhanSo operator - () const {return PhanSo(-tu, mau);}

bool operator == (PhanSo b) const; bool operator != (PhanSo b) const; void Xuat() const;

(8)

Ví dụ minh hoạ – Lớp PhanSo Ví dụ minh hoạ – Lớp PhanSo

void PhanSo::UocLuoc() {

long usc = USCLN(tu, mau); tu /= usc; mau /= usc;

if (mau < 0)

mau = -mau, tu = -tu; if (tu == 0) mau = 1;

(9)

Ví dụ minh hoạ – Lớp PhanSo Ví dụ minh hoạ – Lớp PhanSo

void PhanSo::Set(long t, long m) {

if (m) {

tu = t; mau = m; UocLuoc(); }

9

} }

void PhanSo::Xuat() const {

cout << tu;

(10)

Ví dụ minh hoạ – Lớp PhanSo Ví dụ minh hoạ – Lớp PhanSo

PhanSo PhanSo::Cong(PhanSo b) const {

return PhanSo(tu*b.mau + mau*b.tu, mau*b.mau); }

PhanSo PhanSo::operator + (PhanSo b) const {

return PhanSo(tu*b.mau + mau*b.tu, mau*b.mau); return PhanSo(tu*b.mau + mau*b.tu, mau*b.mau); }

bool PhanSo::operator == (PhanSo b) const {

(11)

Ví dụ minh hoạ – Lớp PhanSo Ví dụ minh hoạ – Lớp PhanSo

Sau định nghĩa phép tốn, ta dùng theo giao

diện tự nhiên: void main() {

PhanSo a(2,3), b(3,4), c(0,1),d(0,1); c = a.Cong(b);

d = a + b; // d = a.operator + (b);

11

(12)

Một số ràng buộc phép toán Một số ràng buộc phép toán

Khi định nghĩa phép tốn khơng thay đổi

đặc tính phép tốn độ ưu tiên, số ngơi; khơng sáng chế phép toán mod, **,…

Hầu hết phép tốn khơng ràng buộc ý nghĩa,

số trường hợp cá biệt phép toán gán (operator =),

lấy phần tử qua số (operator []), phép gọi hàm

lấy phần tử qua số (operator []), phép gọi hàm

(operator ()), phép lấy thành phần (operator ->) đòi hỏi phải định nghĩa hàm thành phần để

toán hạng thứ đối tượng trái (lvalue).

Các phép tốn có sẵn có chế kết hợp suy diễn từ

(13)

Một số ràng buộc phép toán Một số ràng buộc phép tốn

Điều khơng đối phép toán định nghĩa cho

kiểu liệu người sử dụng định nghĩa Nghĩa ta phải chủ động định nghĩa phép toán +=, -=, *=, >>=,… dù định nghĩa phép gán phép toán +,-,*,>>,…

Ràng buộc cho phép người sử dụng chủ động định

nghĩa phép toán trước (+= trước hay + trước).

13

(14)

Hàm thành phần toàn cục Hàm thành phần toàn cục

Trong ví dụ trên, ta định nghóa hàm thành phần có tên

đặc biệt khoá operator theo sau tên phép toán cần định nghĩa Sau định nghĩa phép

tốn, ta dùng theo giao diện tự nhiên: void main()

{

PhanSo a(2,3), b(3,4), c(0,1),d(0,1); PhanSo a(2,3), b(3,4), c(0,1),d(0,1); c = a.Cong(b);

(15)

Hàm thành phần hàm toàn cục Hàm thành phần hàm toàn cục

Trong hầu hết trường hợp, ta định nghĩa phép

tốn thành phần dùng hàm tồn cục.

Khi định nghĩa phép toán hàm thành phần, số tham số

ít số ngơi có tham số ngầm định đối tượng gọi phép toán (toán hạng thứ nhất) Phép tốn ngơi cần tham số phép tốn ngơi khơng có tham số:

a - b;// a.operator -(b);

15

a - b;// a.operator -(b); -a; // a.operator –();

Khi định nghĩa phép tốn hàm tồn cục, số tham số

băng số ngơi, Phép tốn ngơi cần tham số phép tốn một ngơi cần tham số:

(16)

Hàm thành phần hàm toàn cục Hàm thành phần hàm toàn cục

class PhanSo {

long tu, mau; void UocLuoc(); public:

PhanSo(long t, long m) {Set(t,m);} void Set(long t, long m);

16

long LayTu() const {return tu;} long LayMau() const {return mau;} PhanSo operator + (PhanSo b) const;

friend PhanSo operator - (PhanSo a, PhanSo b); PhanSo operator -() const {return PhanSo(-tu,

(17)

Hàm thành phần hàm toàn cục Hàm thành phần hàm toàn cục

PhanSo PhanSo::operator + (PhanSo b) const {

return PhanSo(tu*b.mau + mau*b.tu, mau*b.mau); }

PhanSo operator - (PhanSo a, PhanSo b) {

return PhanSo(a.tu*b.mau - a.mau*b.tu,

17

return PhanSo(a.tu*b.mau - a.mau*b.tu, a.mau*b.mau);

(18)

Hàm thành phần hàm toàn cục Hàm thành phần hàm toàn cục

void main() {

(19)

Hàm thành phần toàn cục Hàm thành phần toàn cục

Khi định nghóa hai cách, dùng hàm thành

phần gọn Tuy nhiên chọn hàm thành phần hay hàm toàn cục hồn tồn tuỳ theo sở thích người sử dụng.

Dùng hàm toàn cục thuận tiện ta có nhu cầu

chuyển kiểu toán hạng thứ nhất.

Các phép toán =, [], (), -> như nói bắt

19

Các phép toán =, [], (), -> như nói bắt

buộc phải định nghĩa hàm thành phần tốn hạng thứ phải lvalue.

Khi định nghĩa phép tốn có tốn hạng thứ thuộc

lớp xét dùng hàm thành phần hàm toàn cục

Tuy nhiên, tốn hạng thứ khơng thuộc lớp

(20)

Ví dụ sử dụng hàm tồn cục Ví dụ sử dụng hàm tồn cục

class PhanSo {

long tu, mau; public:

PhanSo(long t, long m) {Set(t,m);} PhanSo operator + (PhanSo b) const; PhanSo operator + (long b) const PhanSo operator + (long b) const

{return PhanSo(tu + b*mau, mau);} void Xuat() const;

};

PhanSo a(2,3), b(4,1);

(21)

Ví dụ sử dụng hàm tồn cục Ví dụ sử dụng hàm toàn cục

class PhanSo {

long tu, mau; public:

PhanSo(long t, long m) {Set(t,m);} PhanSo operator + (PhanSo b) const; PhanSo operator + (long b) const;

{return PhanSo(tu + b*mau, mau);}

friend PhanSo operator + (long a, PhanSo b);

21

friend PhanSo operator + (long a, PhanSo b); };

PhanSo operator + (long a, PhanSo b)

{ return PhanSo(a*b.mau+b.tu, b.mau); } //

PhanSo a(2,3), b(4,1), c(0,1);

(22)

3 Chuyeån kieåu (type conversions) 3 Chuyeån kieåu (type conversions)

Về mặt khái niệm, ta thực trộn lẫn phân số

và số nguyên phép toán số học quan hệ Chẳng hạn cộng phân số phân số, phân số số nguyên, số nguyên phân số Điều cho phép toán khác trừ, nhân, chia, so sánh Nghĩa ta có nhu cầu định nghĩa phép tốn

+,-,*,/,<,>,==,!=,<=,>= cho phân số số nguyên. ,*,/,<,>,==,!=,<=,>= cho phân số số nguyên.

Sử dụng cách định nghĩa hàm cho phép

toán + làm tương tự cho phép tốn cịn lại ta có thể thao tác phân số số nguyên.

Điều áp dụng tương tự cho kiểu liệu

(23)

Chuyeån kieåu Chuyeån kieåu

class PhanSo {

long tu, mau; public:

PhanSo(long t, long m) {Set(t,m);} void Set(long t, long m);

PhanSo operator + (PhanSo b) const; PhanSo operator + (long b) const;

friend PhanSo operator + (long a, PhanSo b); PhanSo operator - (PhanSo b) const;

23

PhanSo operator - (PhanSo b) const; PhanSo operator - (long b) const;

friend PhanSo operator - (long a, PhanSo b); PhanSo operator * (PhanSo b) const;

PhanSo operator * (long b) const;

friend PhanSo operator * (long a, PhanSo b); PhanSo operator / (PhanSo b) const;

PhanSo operator / (long b) const; // tiep trang sau

(24)

Chuyeån kieåu Chuyeån kieåu

// tiep theo

friend PhanSo operator / (int a, PhanSo b); PhanSo operator -() const;

bool operator == (PhanSo b) const; bool operator == (long b) const;

friend bool operator == (long a, PhanSo b); bool operator != (PhanSo b) const;

24

bool operator != (long b) const;

friend bool operator != (int a, PhanSo b); bool operator < (PhanSo b) const;

bool operator < (long b) const;

friend bool operator < (int a, PhanSo b); bool operator > (PhanSo b) const;

bool operator > (long b) const;

(25)

Chuyeån kieåu Chuyeån kieåu

Với khai báo trên, ta sử dụng phân số

số nguyên lẫn lộn biểu thức: void main()

{

PhanSo a(2,3), b(1,4), c(3,1), d(2,5); a = b * -c;

c = (b+2) * 2/a;

25

c = (b+2) * 2/a;

d = a/3 + (b*c-2)/5; }

Tuy nhiên, viết hàm tương tự lập lập lại

cách tiếp gây mệt mỏi dễ sai sót Ta thể học theo cách chuyển kiểu ngầm định mà C++ áp dụng cho kiểu liệu có sẵn:

double r = 2; // double x = double(2);

(26)

3.1 Chuyển kiểu phương thức thiết lập 3.1 Chuyển kiểu phương thức thiết lập

Khi cần tính tốn biểu thức, kiểu liệu chưa

hồn tồn khớp, trình biên dịch tìm cách chuyển kiểu Trong biểu thức số học, có tham gia tốn hạng thực, thành phần khác chuyển

sang số thưc Các trường hợp khác chuyển kiểu thực hiện theo nguyên tắc nâng cấp (int sang long, float sang double …) Ta học theo cách chuyển kiểu từ số nguyên sang số thực để chuyển từ số nguyên sang phân double …) Ta học theo cách chuyển kiểu từ số nguyên sang số thực để chuyển từ số nguyên sang phân số.

Số nguyên chuyển sang số thực cách ngầm

định cần tạo số thực từ số nguyên. double r = 2; // double r = double(2);

Để chuyển từ số nguyên sang phân số, ta cần dạy

(27)

Chuyển kiểu phương thức thiết lập Chuyển kiểu phương thức thiết lập

Việc tạo phân số từ số nguyên phép gọi phương

thức thiết lập Nói cách khác ta cần xây dựng

phương thức thiết lập để tạo phân số với tham số số nguyên:

class PhanSo {

long tu, mau;

27

long tu, mau; public:

PhanSo(long t, long m) {Set(t,m);}

PhanSo(long t) {Set(t,1);} // Co the chuyen kieu tu so nguyen sang phan so

void Set(long t, long m);

PhanSo operator + (PhanSo b) const;

friend PhanSo operator + (int a, PhanSo b); PhanSo operator - (PhanSo b) const;

(28)

Chuyển kiểu phương thức thiết lập Chuyển kiểu phương thức thiết lập

Phương thức thiết lập với tham số số nguyên

trên hàm ý số nguyên là một phân số, chuyển kiểu ngầm định từ số nguyên sang phân số.

Khi ta giảm bớt việc khai báo định nghĩa

phép toán + phân số số nguyên, chế chuyển kiểu tự động cho phép thực thao tác cộng đó, nói cách

khác giảm việc định nghĩa phép tốn xuống cịn khác giảm việc định nghĩa phép tốn xuống cịn 2:

//

PhanSo a(2,3), b(4,1), c(0);

PhanSo d = 5; // PhanSo d = PhanSo(5); // PhanSo d(5);

c = a + b; // c = a.operator + (b): Ok

(29)

Chuyển kiểu phương thức thiết lập Chuyển kiểu phương thức thiết lập

Ta giảm số phép tốn cần định nghĩa từ xuống

bằng cách dùng hàm toàn cục, chuyển kiểu cả hai toán hạng.

class PhanSo {

long tu, mau; public:

29

public:

PhanSo(long t, long m) {Set(t,m);}

PhanSo(long t) {Set(t,1);} // Co the chuyen kieu tu so nguyen sang phan so

void Set(long t, long m);

friend PhanSo operator + (PhanSo a, PhanSo b); friend PhanSo operator - (PhanSo a, PhanSo b); //

(30)

Chuyển kiểu phương thức thiết lập Chuyển kiểu phương thức thiết lập

Khi chế chuyển kiểu thực cho

hai toán hạng. //

PhanSo a(2,3), b(4,1), c(0);

PhanSo d = 5; // PhanSo d = PhanSo(5); c = a + b; // c = operator + (a,b): Ok

c = a + 5; // c = operator + (a,PhanSo(5)): Ok c = a + 5; // c = operator + (a,PhanSo(5)): Ok

// Hay c = a + PhanSo(5);

c = + a; // c = operator + (PhanSo(3),a): Ok // Hay c = PhanSo(3) + a

(?) Neáu vieát

c = + 7;

(31)

Hai cách chuyển kiểu phương thức thiết lập Hai cách chuyển kiểu phương thức thiết lập Chuyển kiểu phương thức thiết lập thực

theo nguyên tắc tạo đối tượng (phân số) từ đối tượng có (số nguyên) Điều thực theo cách nêu trên, dùng phương thức thiết lập với tham số có giá trị mặc nhiên.

class PhanSo { class PhanSo { 31 {

long tu, mau; public:

PhanSo(long t, long m) {Set(t,m);} PhanSo(long t) {Set(t,1);} // }; {

long tu, mau; public:

PhanSo(long t, long m = 1) {Set(t,m);}

(32)

Khi chuyển kiểu phương thức thiết lập Khi chuyển kiểu phương thức thiết lập Ta dùng chuyển kiểu phương thức thiết lập

thoả hai điều kiện sau:

1 Chuyển từ kiểu có (số nguyên) sang kiểu định nghĩa (phân số)

2 Có quan hệ từ kiểu có sang kiểu định nghĩa (một số nguyên phân số)

Các ví dụ dùng chuyển kiểu phương thức thiết lập Các ví dụ dùng chuyển kiểu phương thức thiết lập

(33)

3.2 Chuyển kiểu phép toán chuyển kiểu 3.2 Chuyển kiểu phép toán chuyển kiểu

Sử dụng phương thức thiết lập để chuyển kiểu

tiện lợi số trường hợp có số nhược điểm:

1 Muốn chuyển từ kiểu định nghĩa sang kiểu có, ta phải sửa đổi kiểu có

2 Khơng thể chuyển từ kiểu định nghĩa sang kiểu có sẵn

33 saün

3 Phương thức thiết lập với tham số dẫn đến chế chuyển kiểu tự động khơng mong muốn

Các nhược điểm khắc phục cách

định nghĩa phép toán chuyển kiểu

Phép tốn chuyển kiểu hàm thành phần có dạng

X::operator T()

(34)

Dùng phép toán chuyển kiểu Dùng phép toán chuyển kiểu

Ta dùng phép toán chuyển kiểu định nghĩa kiểu muốn tận

dụng phép toán kiểu có

class String {

char *p; public:

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

String(const String &s2) {p = strdup(s2.p);}

34

String(const String &s2) {p = strdup(s2.p);} ~String() {delete [] p;}

String& operator = (const String& p2); int Length() const {return strlen(p);} void ToUpper() {strupr(p);}

friend ostream& operator << (ostream &o, const String& s);

(35)

Dùng phép toán chuyển kiểu Dùng phép toán chuyển kiểu

ostream & operator << (ostream &o, const String& s) {

return o << s.p; }

void main() {

String s("Nguyen van A");

35

cout << s.Length() << "\n"; cout << strlen(s) << "\n";

if (strcmp(s, "Nguyen van A") == 0) cout << "Hai chuoi bang nhau\n"; else

cout << "Hai chuoi khac nhau\n"; strupr(s);

(36)

Ví dụ phép tốn chuyển kiểu Ví dụ phép tốn chuyển kiểu

Ví dụ sau minh hoạ rõ thêm nhu cầu chuyển kiểu Một

NumStr chuyển sang số thực. class NumStr

{

char *s; public:

NumStr(char *p) {s = dupstr(p);} NumStr(char *p) {s = dupstr(p);}

operator double() {return atof(s);}

friend ostream & operator << (ostream &o, NumStr &ns);

};

ostream & operator << (ostream &o, NumStr &ns) {

(37)

Ví dụ phép tốn chuyển kiểu Ví dụ phép toán chuyển kiểu

void main() {

NumStr s1("123.45"), s2("34.12"); cout << "s1 = " << s1 << "\n";

// Xuat 's1 = 123.45' cout cout << "s2 = " << s2 << "\n";

// Xuat 's2 = 34.12' cout

37

// Xuat 's2 = 34.12' cout

cout << "s1 + s2 = " << s1 + s2 << "\n"; // Xuat 's1 + s2 = 157.57' cout

cout << "s1 + 50 = " << s1 + 50 << "\n"; // Xuat 's1 + 50 = 173.45' cout

cout << "s1 * = " << s1 * << "\n"; // Xuat 's1 * = 246.9' cout

cout << "s1 / = " << s1 / << "\n"; // Xuat 's1 / = 61.725' cout

(38)

Dùng phép toán chuyển kiểu Dùng phép toán chuyển kiểu

Phép toán chuyển kiểu dùng để biểu diễn quan hệ

từ kiểu định nghĩa sang kiểu có

class PhanSo {

long tu, mau; void UocLuoc(); public:

PhanSo(long t = 0, long m = 1) {Set(t,m);} void Set(long t, long m);

friend PhanSo operator + (PhanSo a, Pham So b); void Xuat() const;

operator double() const {return double(tu)/mau;} };

//

PhanSo a(9,4);

cout << sqrt(a) << “\n”;

(39)

4 Một số phép tốn thơng dụng 4 Một số phép tốn thơng dụng

Một số phép toán C++ định nghĩa lại với ý nghĩa

mới Ví dụ << >> hai phép toán C++ định nghĩa lại để sử dụng với dòng xuất, nhập áp dụng cho kiểu bản.

Ta định nghĩa lại << >> để thực

các thao tác xuất nhập cho kiểu liệu mới.

Ngoài ra, việc định nghĩa phép tốn thơng dụng

39

Ngồi ra, việc định nghĩa phép tốn thơng dụng

(40)

5.1 Phép toán << >> 5.1 Phép toán << >>

<< >> hai phép toán thao tác bit

toán hạng số nguyên.

C++ định nghĩa lại hai phép toán để dùng với đối

tượng thuộc lớp ostream istream để thực thao tác xuất, nhập.

Khi định nghĩa hai phép toán trên, cần thể ý nghĩa

sau:

40

sau:

a >> b; // bỏ a vào b a << b; // bỏ b vào a

cout << a << “\n”; // bo a va “\n” vao cout cin >> a >> b; // bo cin vao a va b

Lớp ostream (dòng liệu xuất) định nghĩa phép toán <<

áp dụng cho kiểu liệu (nguyên, thực, char *,…).

(41)

Phép toán << >> Phép toán << >>

cout, cerr biến thuộc lớp ostream đại diện cho

thiết bị xuất chuẩn (mặc nhiên hình) thiết bị báo lỗi chuẩn (luôn hình).

cin đối tượng thuộc lớp istream đại diện cho thiết

bị nhập chuẩn, bàn phím.

Với khai báo lớp ostream ta thực

phép toán << với toán hạng thứ dòng liệu

41

phép tốn << với tốn hạng thứ dịng liệu xuất (cout, ceer, tập tin…), toán hạng thứ hai thuộc kiểu (nguyên, thực, char *, trỏ…).

Tương tự, ta áp dụng phép toán >> với toán hạng

(42)

Lớp ostream Lớp ostream

class ostream : virtual public ios {

public:

// Formatted insertion operations

ostream & operator<< ( signed char); ostream & operator<< (unsigned char); ostream & operator<< (int);

42

ostream & operator<< (unsigned int); ostream & operator<< (long);

ostream & operator<< (unsigned long); ostream & operator<< (float);

ostream & operator<< (double);

ostream & operator<< (const signed char *); ostream & operator<< (const unsigned char *); ostream & operator<< (void *);

(43)

Lớp istream Lớp istream

class istream : virtual public ios {

public:

istream & getline(char *, int, char = '\n'); istream & operator>> ( signed char *);

istream & operator>> (unsigned char *); istream & operator>> (unsigned char &);

43

istream & operator>> ( signed char &); istream & operator>> (short &);

istream & operator>> (int &); istream & operator>> (long &);

istream & operator>> (unsigned short &); istream & operator>> (unsigned int &); istream & operator>> (unsigned long &); istream & operator>> (float &);

(44)

Phép toán << >> Phép toán << >>

Để định nghĩa phép tốn << theo nghĩa xuất dịng

liệu xuất cho kiểu liệu định nghĩa, ta định nghĩa phép toán hàm toàn cục với tham số thứ

tham chiếu đến đối tượng thuộc lớp ostream, kết trả tham chiếu đến ostream đó Toán hạng thứ hai thuộc lớp định nghĩa

Để định nghĩa phép toán >> theo nghĩa nhập từ dòng Để định nghĩa phép tốn >> theo nghĩa nhập từ dịng

dữ liệu nhập cho kiểu liệu định nghĩa, ta định nghĩa phép tốn >> hàm tồn cục với tham số thứ nhất tham chiếu đến đối tượng thuộc lớp

istream, kết trả tham chiếu đến istream

đó Toán hạng thứ hai tham chiếu đến đối tượng thuộc lớp định nghĩa.

(45)

Ví dụ định nghĩa << >> cho lớp phân số Ví dụ định nghĩa << >> cho lớp phân số

// phanso.h class PhanSo {

long tu, mau; void UocLuoc(); public:

PhanSo(long t = 0, long m = 1) {Set(t,m);}

45

void Set(long t, long m);

long LayTu() const {return tu;} long LayMau() const {return mau;}

friend PhanSo operator + (PhanSo a, PhanSo b); friend PhanSo operator - (PhanSo a, PhanSo b); friend PhanSo operator * (PhanSo a, PhanSo b); friend PhanSo operator / (PhanSo a, PhanSo b);

(46)

Phép toán << >> Phép toán << >>

// phanso.cpp

#include <iostream.h> #include “phanso.h”

istream & operator >> (istream &is, PhanSo &p) {

is >> p.tu >> p.mau; while (!p.mau)

{

cout << “Nhap lai mau so: ”; is >> p.mau;

is >> p.mau; }

p.UocLuoc();

return is;

}

ostream & operator << (ostream &os, PhanSo p) {

os << p.tu;

if (p.tu != && p.mau != 1) os << "/" << p.mau;

(47)

Phép toán << >> Phép toán << >>

// tps.cpp

#include <iostream.h> #include “phanso.h” void main()

{

PhanSo a, b;

cout << “Nhap phan so a: ”; cin >> a;

47

cout << “Nhap phan so b: ”; cin >> b;

(48)

Ví dụ phép tốn << >>: Lớp String Ví dụ phép toán << >>: Lớp String

class String {

char *p; public:

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

String(const String &s2) {p = strdup(s2.p);} ~String() {delete [] p;}

String& operator = (const String& p2);

friend String operator +(const String &s1, const String &s2);

friend istream& operator >> (istream &i, String& s);

friend ostream& operator << (ostream &o, const String& s);

(49)

Ví dụ phép tốn << >>: Lớp String Ví dụ phép tốn << >>: Lớp String

const MAX = 512;

istream & operator >> (istream &is, String& s) {

char st[MAX];

is.getline(st,sizeof(s)); is.ignore();

s = st;

49

return is; }

ostream & operator << (ostream &o, const String& s) {

(50)

Phép toán << >> Phép toán << >>

Phép tốn << >> định nghĩa với

toán hạng thứ thuộc lớp xét, không thuộc lớp ostream istream Trong trường hợp đó, ta dùng hàm thành phần Kiểu trả đối tượng vế trái để có thể thực phép tốn liên tiếp.

Các ví dụ sử dụng phép tốn theo cách

các lớp Stack, Tập hợp, Danh sách, Mảng, Tập tin… các lớp Stack, Tập hợp, Danh sách, Mảng, Tập tin…

Mang a;

a << << 15; // bỏ 15 vào mảng

Ví dụ sau minh hoạ cách sử dụng phép toán với lớp

(51)

Phép toán << >> Phép toán << >>

class Stack {

Item *st, *top; int size;

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

public:

51

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

(52)

Phép toán << >> Phép toán << >>

void main() {

Stack s(10);

Item a,b,c,d,e;

a = b = c = d = e = 10; s << << << << 7; s << << << << 7;

s >> a >> b >> c >> d >> e;

cout << setw(4) << a << setw(4) << b <<

setw(4) << c << setw(4) << d << setw(4) << e << "\n";

}

(53)

5.2 Phép toán lấy phần tử mảng: [] 5.2 Phép toán lấy phần tử mảng: []

Ta định nghĩa phép toán [] để truy xuất phần tử

một đối tượng có ý nghĩa mảng. class String

{

friend ostream& operator << (ostream &o, const String& s);

char *p;

53

public:

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

String(const String &s) {p = strdup(s.p);} ~String() {delete [] p;}

String & operator = (const String &s); char & operator[](int i) {return p[i];} };

Kết trả tham chiếu để phần tử trả đứng

(54)

Phép toán lấy phần tử mảng: [] Phép toán lấy phần tử mảng: []

Sau định nghĩa trên, sử dụng đối tượng trả

về hai vế phép toán gán. void main()

{

clrscr();

String a("Nguyen van A");

cout << a[7] << "\n"; // a.operator[](7) cout << a[7] << "\n"; // a.operator[](7) a[7] = 'V';

cout << a[7] << "\n"; // a.operator[](7) cout << a << "\n";

}

Ta cải tiến để phép tốn sử dụng

(55)

Phép toán lấy phần tử mảng: [] Phép toán lấy phần tử mảng: []

Sử dụng phép toán giá trị trái (lvalue) với số

khơng hợp lệ thường gây lỗi khó tìm sửa Ta có thể khắc phục cách kiểm tra.

class String {

char *p;

static char c;

55

static char c; public:

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

String(const String &s) {p = strdup(s.p);} ~String() {delete [] p;}

String & operator = (const String &s);

char & operator[](int i) {return (i >= && i < strlen(p)) ? p[i] : c;}

};

(56)

Phép toán lấy phần tử mảng: [] Phép toán lấy phần tử mảng: []

Sau định nghóa trên, ta “yên trí” gán vào

các phần tử có số khơng hợp lệ. void main()

{

clrscr();

String a("Nguyen van A"); cout << a[7] << "\n";

56

cout << a[7] << "\n"; a[7] = 'V';

cout << a[7] << "\n";

cout << a[200] << "\n"; // Xuat String::c a[200] = 'X'; // Gan String::c = 'X';

cout << a[300]; // Xuat String::c }

Phép tốn [] định nghĩa hoạt động tốt

(57)

Phép toán [] cho đối tượng hằng Phép toán [] cho đối tượng hằng

Tuy nhiên sử dụng phép toán [] không hợp lệ

đối với đối tượng hằng. void main()

{

clrscr();

String a("Nguyen van A");

const String aa("Dai Hoc Tu Nhien");

57

const String aa("Dai Hoc Tu Nhien"); cout << a[7] << "\n";

a[7] = 'V';

cout << a[7] << "\n";

cout << aa[4] << "\n";// Bao Loi: sai khai niem aa[4] = 'L'; // Bao Loi: tot

cout << aa[4] << "\n";// Bao Loi: sai khai niem cout << aa << "\n";

(58)

Phép toán [] cho đối tượng hằng Phép toán [] cho đối tượng hằng

Lỗi khắc phục cách định nghĩa phiên

bản áp dụng cho đối tượng hằng. class String

{

char *p;

static char c; public:

public:

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

String(const String &s) {p = strdup(s.p);} ~String() {delete [] p;}

String & operator = (const String &s);

char & operator[](int i) {return (i >= && i < strlen(p)) ? p[i] : c;}

(59)

Phép toán [] cho đối tượng hằng Phép tốn [] cho đối tượng hằng

Khi việc sử dụng phép toán [] để đọc phần tử hợp lệ

nhưng cố tính gán gây lỗi sai lúc biên dịch. void main()

{

clrscr();

String a("Nguyen van A");

const String aa("Dai Hoc Tu Nhien");

59

const String aa("Dai Hoc Tu Nhien"); cout << a[7] << "\n";

a[7] = 'V';

cout << a[7] << "\n"; cout << aa[4] << "\n";

// String::operator[](int) const : Ok aa[4] = 'L'; // Bao Loi: Khong the la lvalue cout << aa[4] << "\n";

// String::operator[](int) const : Ok cout << aa << "\n"; //

(60)

5.3 Phép toán gọi hàm: () 5.3 Phép toán gọi hàm: ()

Phép tốn [] có tham số, dùng phép

tốn khơng thuận tiện ta muốn lấy phần tử một ma trận hai chiều Phép tốn gọi hàm cho phép có thể có số tham số bất kỳ, thuận tiện ta muốn truy xuất phần tử đối tượng thuộc loại mảng hai hay nhiều chiều hơn.

Lớp ma trận sau định nghĩa phép toán () với hai tham Lớp ma trận sau định nghĩa phép toán () với hai tham

(61)

Phép toán gọi hàm Phép toán gọi hàm

class Matrix {

int m,n;

double *px;

int DataSize(){return m*n*sizeof(double);} void CopyData(double *pData)

{memcpy(px,pData,DataSize());}

void Create(int mm, int nn, double *pData = NULL);

61

void Create(int mm, int nn, double *pData = NULL); public:

Matrix(int mm, int nn, double *_px) {Create(mm,nn,_px);}

Matrix(const Matrix &m2){Create(m2.m,m2.n,m2.px);} ~Matrix() { delete [] px;}

Matrix operator = (const Matrix &m2);

double &operator()(int i, int j){return px[i*n+j];} double operator()(int i, int j) const

(62)

Phép toán gọi hàm () Phép toán gọi hàm ()

Sau định nghĩa phép tốn gọi hàm trên, ta

sử dụng ma trận mảng hai chiều. void main()

{

double a[] = {1,2,3,4,5,6}; Matrix m(2, 3, a);

cout << "m = " << m << "\n"; cout << "m = " << m << "\n";

cout << m(1,2) << "\n"; // m.operator()(1,2) m(1,2) = 50;

cout << m(1,2) << "\n"; }

Phép toán gọi hàm dùng dạng vắn tắt

(63)

Phép toán gọi hàm () Phép toán gọi hàm ()

class String {

friend ostream& operator<<(ostream &o,const String& s); char *p;

static char c; public:

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

63

String(const String &s) {p = strdup(s.p);} ~String() {delete [] p;}

String & operator = (const String &s); void Output() const {cout << p;}

char & operator[](int i) {return (i >= && i < strlen(p)) ? p[i] : c;}

char operator[](int i) const {return p[i];}

String SubStr(int start, int count) const;

String operator()(int start, int count) const;

(64)

Phép toán gọi hàm () Phép toán gọi hàm ()

String String::SubStr(int start, int count) const {

char buf[512];

strncpy(buf, p+start, count); buf[count] = '\0'; return buf;

}

String String::operator()(int start, int count) const

64

{

char buf[512];

strncpy(buf, p+start, count); buf[count] = '\0'; return buf;

}

void main(){

String a("Nguyen van A");

(65)

5.4 Phép toán tăng giảm: ++ −−−−−−−− 5.4 Phép toán tăng giảm: ++ −−−−−−−−

++ là phép tốn ngơi có vai trị tăng giá trị đối

tượng lên giá trị Tương tự −− là phép tốn ngơi có vai trị giảm giá trị đối tượng xuống giá trị trước đó.

++ –– áp dụng cho kiểu liệu đếm được,

nghĩa giá trị đối tượng có giá trị hoặc giá trị trước đó.

65

hoặc giá trị trước đó.

++ –– dùng theo hai cách, tiếp đầu ngữ

hoặc tiếp vĩ ngữ.

Khi dùng tiếp đầu ngữ, ++a có hai vai trị: • Tăng a lên giá trị

• Trả tham chiếu đến a

Khi dùng tiếp vĩ ngữ, a++ có hai vai trị: • Tăng a lên giá trị

(66)

Phép toán tăng giảm: ++ −−−−−−−− Phép toán tăng giảm: ++ −−−−−−−−

Khi định nghĩa phiên phép toán ++ (hay

––) phiên dùng cho hai trường hợp: tiếp đầu ngữ tiếp vĩ ngữ.

class ThoiDiem {

long tsgiay;

static bool HopLe(int g, int p, int gy);

66

static bool HopLe(int g, int p, int gy); public:

ThoiDiem(int g = 0, int p = 0, int gy = 0); 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 Tang(); void Giam();

(67)

Phép toán tăng giảm: ++ −−−−−−−− Phép toán tăng giảm: ++ −−−−−−−−

void ThoiDiem::Tang() {

tsgiay = ++tsgiay%SOGIAY_NGAY; }

void ThoiDiem::Giam() {

if ( tsgiay < 0) tsgiay = SOGIAY_NGAY-1;

67

}

ThoiDiem &ThoiDiem::operator ++() {

Tang();

(68)

3.8 Phép toán tăng giảm: ++ −−−−−−−− 3.8 Phép toán tăng giảm: ++ −−−−−−−−

void main() {

clrscr();

ThoiDiem t(23,59,59),t1,t2; cout << "t = " << t << "\n"; t1 = ++t; // t.operator ++();

// t = 0:00:00, t1 = 0:00:00

cout << "t = " << t << "\tt1 = " << t1 << "\n"; t1 = t++; // t.operator ++();

// t = 0:00:01, t1 = 0:00:00

(69)

Phép toán tăng giảm: ++ −−−−−−−− Phép toán tăng giảm: ++ −−−−−−−−

Để có phép toán ++ –– hoạt động khác

cho hai cách dùng (++a a++) ta cần định nghĩa hai phiên ứng với hai cách dùng kể Phiên tiếp đầu ngữ có thêm tham số giả để phân biệt.

class ThoiDiem{ long tsgiay; public:

69

public:

ThoiDiem(int g = 0, int p = 0, int gy = 0); 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 Tang(); void Giam();

(70)

Phép toán tăng giảm: ++ −−−−−−−− Phép toán tăng giảm: ++ −−−−−−−−

void ThoiDiem::Tang() {

tsgiay = ++tsgiay%SOGIAY_NGAY; }

void ThoiDiem::Giam() {

if ( tsgiay < 0) tsgiay = SOGIAY_NGAY-1; }

70 }

ThoiDiem &ThoiDiem::operator ++() {

Tang();

return *this; }

ThoiDiem ThoiDiem::operator ++(int) {

ThoiDiem t = *this; Tang();

(71)

Phép toán tăng giảm: ++ −−−−−−−− Phép toán tăng giảm: ++ −−−−−−−−

void main() {

clrscr();

ThoiDiem t(23,59,59),t1,t2; cout << "t = " << t << "\n"; t1 = ++t; // t.operator ++();

// t = 0:00:00, t1 = 0:00:00

71

cout << "t = " << t << "\tt1 = " << t1 << "\n"; t1 = t++; // t.operator ++(int);

// t = 0:00:01, t1 = 0:00:00

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