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

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