Bài giảng Lập trình hướng đối tượng - Chương 4: Đa năng hoá toán tử - Trần Minh Thái
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình hướng đối tượng - Chương 4: Đa năng hoá toán tử - Trần Minh Thái", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Tài liệu đính kèm:
- bai_giang_lap_trinh_huong_doi_tuong_chuong_4_da_nang_hoa_toa.pptx
Nội dung text: Bài giảng Lập trình hướng đối tượng - Chương 4: Đa năng hoá toán tử - Trần Minh Thái
- Chương 4 Đa năng hoá toán tử TRẦN MINH THÁI Email: minhthai@itc.edu.vn Website: www.minhthai.edu.vn Cập nhật: 10 tháng 02 năm 2015
- Nội dung #2 1. Giới thiệu 2. Cách cài đặt & sử dụng đa năng hoá toán tử 3. Một số kỹ thuật đa năng hoá toán tử đặc biệt
- Giới thiệu (1/3) #3 Đa năng hóa toán tử là khả năng của C++ cho phép định nghĩa lại toán tử (+, -, *, / , ) trên kiểu dữ liệu khác → Chương trình ngắn gọn, dễ đọc và có ý nghĩa hơn so với việc gọi hàm bình thường Đa năng hóa toán tử bằng cách định nghĩa hoạt động của từng toán tử giống như định nghĩa một hàm → hàm toán tử
- Giới thiệu (2/3) #4 Cú pháp: type_name operator operator_symbol ( parameters_list ) { } Hàm toán tử ▪ Hàm toàn cục (hàm tự do) → hàm friend ▪ Hàm thành viên của lớp (hàm non-static) → có thuộc tính truy xuất public
- Giới thiệu (3/3) #5 Khai báo Cú pháp khi gọi Hàm thành viên Hàm toàn cục aa#bb aa.operator#(bb) operator#(aa,bb) #aa aa.operator#() operator#(aa) aa# aa.operator#(int) operator#(aa,int) Với # là ký hiệu dấu toán tử
- Các lưu ý (1/) #6 Không thể định nghĩa toán tử mới Phần lớn các toán tử được đa năng hóa ngoại trừ các toán tử sau: . .* :: ?: typeid sizeof const_cast dynamic_cast reinterpret_cast static_cast Không thể đa năng hóa ký hiệu tiền xử lý Không thể thay đổi độ ưu tiên của toán tử hay số các toán hạng của nó
- Các lưu ý (2/) #7 Không thể thay đổi ý nghĩa của toán tử khi áp dụng các kiểu cài sẵn Không dùng tham số có giá trị mặc định Các toán tử: = [] () -> đòi hỏi hàm toán tử phải là hàm thành viên Phải chủ động định nghĩa toán tử += -= *= /= dù đã định nghĩa + - * /
- Tham số (1/2) #8 Số lượng các tham số của hàm toán tử phụ thuộc: Toán tử một ngôi hay hai ngôi Toán tử được khai báo là hàm toàn cục hoặc hàm thành viên
- Tham số (2/2) #9 Nên sử dụng tham chiếu khi có thể (đối tượng lớn) Luôn sử dụng tham số hằng tham chiếu nếu tham số không bị sửa đổi bool CComplex::operator == (const CComplex & c) const; Hàm thành viên nên khai báo là hàm thành viên hằng nếu toán hạng đầu tiên không bị sửa đổi Các toán tử tính toán/ so sánh → thường dùng hằng tham chiếu
- Giá trị trả về #10 Tuân thủ theo đặc điểm chung của các cài đặt có sẵn của toán tử Các phép so sánh (==, != ) thường trả về giá trị kiểu bool → phiên bản đa năng hóa cũng nên trả về bool Giá trị trả về có thể là hằng hoặc tham chiếu tuỳ theo ngữ cảnh
- Ví dụ hàm toán tử thành viên (1/3) class CComplex #11 { private: double real, image; public: CComplex (double r = 0, double i=0) { real = r; image = i; } void Print() const; void Println() const; CComplex operator + (CComplex c) const; CComplex operator + (double r) const; }; void CComplex::Print() const { cout<<"["<<real<<","<<image<<"]"; }
- Ví dụ hàm toán tử thành viên (2/3) #12 void CComplex::Println() const { Print(), cout<<endl; } CComplex CComplex::operator + (CComplex c ) const { CComplex tmp; tmp.real = real + c.real; tmp.image = image + c.image; return tmp; } CComplex CComplex::operator + (double r) const { CComplex tmp; tmp.real = real + r; tmp.image = image; return tmp; }
- Ví dụ hàm toán tử thành viên (3/3) #13 CComplex c1 (3,5), c2(3, -2); CComplex c3, c4; c3 = c1 + c2; //OK: c3 = c1.operator + (c2) c1.Print(), cout<<"+", c2.Print(),cout<<"=", c3.Println(); c4 = c2 + 4.5; //OK: c4 = c2.operator + (4.5) c2.Print(), cout<<"+ 4.5 =", c4.Println(); c3.Print(), cout<<"+", c4.Print(),cout<<"=", (c3 + c4).Println(); //OK c4 = 4.5 + c1; //Error vì 4.5 không phải là đối tượng của CComplex
- Ví dụ hàm toán tử friend (1/5) #14 class CComplex { private : double real, image; public : CComplex(); CComplex (double r, double i); CComplex (double r); //constructor chuyển kiểu: double → CComplex CComplex (const CComplex &c ); //constructor sao chép void Print() const; void Println() const; friend CComplex operator + ( CComplex c1, CComplex c2 ); friend CComplex operator - ( CComplex c1, CComplex c2 ); CComplex operator += (CComplex c); friend bool operator == (CComplex c1, CComplex c2); };
- Ví dụ hàm toán tử friend (2/5) CComplex::CComplex() #15 { real = image = 0.0; } CComplex::CComplex(double r, double i) { real = r; image = i; } CComplex::CComplex(double r) { real = r; image= 0.0; } CComplex::CComplex(const CComplex &c) { real = c.real; image = c.image; }
- Ví dụ hàm toán tử friend (3/5) #16 void CComplex::Print() const { cout<<"["<<real<<","<<image<<"]"; } void CComplex::Println() const { Print(), cout<<endl; } CComplex operator + (CComplex c1, CComplex c2) { CComplex tmp; tmp.real = c1.real + c2.real; tmp.image = c1.image + c2.image; return tmp; }
- Ví dụ hàm toán tử friend (4/5) CComplex operator - (CComplex c1, CComplex c2) #17 { CComplex tmp; tmp.real = c1.real - c2.real; tmp.image = c1.image - c2.image; return tmp; } bool operator == (CComplex c1, CComplex c2) { return (c1.real==c2.real)&&(c1.image==c2.image); } CComplex CComplex::operator += (CComplex c) { real+=c.real; image+=c.image; return *this; }
- Ví dụ hàm toán tử friend (5/5) #18 CComplex c1 (3,5), c2(3, -2); CComplex c3, c4; c3 = c1 + c2; //OK: c3 = operator + (c1,c2) c1.Print(), cout Ket qua:", c4.Println();
- Ví dụ đa năng hoá toán tử 1 ngôi (1/2) Gồm các toán tử: + - ! ++ -> ~ * & #19 class CComplex { private : double real, image; public : CComplex(); CComplex (double r, double i); CComplex (double r); CComplex (const CComplex &c ); //constructor sao chép void Print() const; friend CComplex operator + ( CComplex c1, CComplex c2 ); friend CComplex operator - ( CComplex c1, CComplex c2 ); friend bool operator == (CComplex c1, CComplex c2); CComplex operator += (CComplex c); CComplex operator - (); };
- Ví dụ đa năng hoá toán tử 1 ngôi (2/2) #20 CComplex CComplex::operator-() { CComplex tmp; tmp.real = -real; tmp.image = -image; return tmp; }
- Ví dụ đa năng hoá toán tử đặc biệt (1/3) #21 Gồm các toán tử: ▪ () [] ++ , = -> ▪ Toán tử chuyển kiểu ▪ Toán tử new và delete Toán tử [] và () ▪ []: chỉ có hai tham số ▪ (): số các tham số bất kỳ
- Ví dụ đa năng hoá toán tử đặc biệt (2/3) #22 class CVector CVector::CVector(int s) { { private: size = s; int size; data = new int[size]; int *data; for(int i=0;i<size;++ i) public: data[i] = i + 1; CVector(int s = 2); } ~CVector(); CVector::~CVector() int & operator[](int i); { int & operator()(int i); delete [] data; }; }
- Ví dụ đa năng hoá toán tử đặc biệt (3/3) #23 int & CVector::operator[](int i) { CVector v(10); return data[i]; cout<<v(5)<<","<<v[7]; } v[4] = 10; int & CVector::operator()(int i) { return data [i]; }
- Đa năng hoá toán tử tăng/ giảm (1/2) #24 Tiền tố và hậu tố phân biệt qua số ngôi Tiền tố là toán tử một ngôi Hậu tố là toán tử hai ngôi (tham số thứ hai kiểu int) #aa aa.operator#() operator#(aa) aa# aa.operator#(int) operator#(aa,int)
- Đa năng hoá toán tử tăng/ giảm (2/2) #25 class CMyPoint CMyPoint CMyPoint::operator ++() { { private: ++x; int x, y; ++y; public: return *this; CMyPoint(int a = 0 , int b = 0 ); } CMyPoint operator ++(); CMyPoint CMyPoint::operator ++(int) CMyPoint operator ++(int); { }; return operator ++(); CMyPoint::CMyPoint(int a, int b ) } { x = a; y = b; }
- Toán tử -> #26 Truy xuất thành viên dưới dạng con trỏ class CMyClass { public: CMyClass m ; int data ; cout () cout data; { return this; } }
- Toán tử phẩy (,) class CMyPoint #27 { private: int x, y; Là toán tử public: CMyPoint(int a = 0 , int b = 0 ) hai ngôi { x = a; Có giá trị là y = b; } giá trị của CMyPoint operator ,(CMyPoint); }; biểu thức CMyPoint CMyPoint :: operator , (CMyPoint p) { cuối cùng CMyPoint tmp ; tmp.x = p.x ; tmp.y = p.y ; return tmp ; }
- Toán tử gán (1/2) #28 class A { private: Phép gán và int *data; public: constructor sao A(int x) { chép chỉ thực hiện data = new int(x); } sao chép đơn giản ~A() { (shallow copy) delete data; } void Print(char *st) { cout<<st<<"data:"<<*data<<endl; } };
- Toán tử gán (2/2) #29 (instance) a A A *a = new A(5); new A(5) a->Print("a."); data 5 ? (instance) A A b(10); b.Print("b."); data 10 ? b = *a; b.Print("b."); delete a; b.Print("b."); //runtime error
- Đa năng hoá toán tử gán (1/3) #30 Đa năng hóa toán tử gán chỉ cần thiết khi ▪ Sao chép có xử lý bên trong (deep copy) – chẳng hạn sử dụng bộ nhớ động ▪ Sao chép đòi hỏi cả tính toán – chẳng hạn gán một số hiệu có giá trị duy nhất/ tăng số đếm, Hàm toán tử của toán tử gán phải trả về một tham chiếu của đối tượng bên phải của phép gán
- Đa năng hoá toán tử gán (2/3) #31 class CMyString ~CMyString() { { char *str; free(str); public: } CMyString(char *s = "") CMyString & operator = (const CMyString &s); { void Output() const str = strdup(s); { } cout <<str<<endl; CMyString(const CMyString &s) } { }; //End of CMyString str = strdup(s.str); }
- Đa năng hoá toán tử gán (3/3) #32 CMyString & CMyString::operator = (const CMyString &s) { CMyString s1("AAAA"); if (this != &s) CMyString s2 = s1; { s1 = "BBBB"; free(str); //giải phóng vùng nhớ cũ s1.Output(); str = strdup(s.str); //sao chép mới s2.Output(); } return *this; } Đối tượng có thành viên dữ liệu động, khi đa năng hóa toán tử gán thì cần phải có thêm ba phương thức sau: ▪ Constructor ▪ Constructor sao chép ▪ Destructor
- Đa năng hoá toán tử new & delete (1/3) #33 Thay thế hẳn các toán tử này → Hàm toàn cục Chỉ áp dụng cho đối tượng của một lớp → Hàm thành viên của lớp Cú pháp ▪ void * operator new(size_t size); ▪ void operator delete(void * ptr);
- Đa năng hoá toán tử new & delete (2/3) void * operator new(size_t size) { #34 return malloc(size); } Hàm toàn cục void operator delete(void *ptr) { class CMyPoint free(ptr); { } int x, y; public: CMyPoint *p1,*p2; CMyPoint(int a=0,int b=0) p1 = new CMyPoint(10,20); { p2 = new CMyPoint(-10,-20); x=a; int *x=new int; y=b; *x=10; } cout Print(); cout Print(); }; delete p1; delete p2; delete x;
- Đa năng hoá toán tử new & delete (3/3) void operator delete(void *ptr) #35 { cout Print(); delete n; delete x;
- Toán tử chuyển kiểu (1/5) #36 Có hai toán tử chuyển kiểu Ngầm định: sử dụng constructor chuyển kiểu (có một tham số duy nhất là tham số kiểu cần chuyển đổi) Tường minh: sử dụng toán tử chuyển kiểu
- Toán tử chuyển kiểu (2/5) #37 Chuyển kiểu ngầm định class CComplex { private : double real, image; public : CComplex (double r) //constructor chuyển kiểu: double → CComplex { real = r; image = 0; CComplex c = 6.5; //Chuyển kiểu ngầm định } };
- Toán tử chuyển kiểu (3/5) #38 Nếu muốn ngăn chặn chuyển kiểu tự động, dùng từ khoá explicit khi khai báo constructor class CComplex { private : double real, image; public : explicit CComplex (double r) { real = r; image = 0; } CComplex c = CComplex(6.5); };
- Toán tử chuyển kiểu (4/5) #39 Toán tử chuyển kiểu Là thành viên của lớp cần chuyển kiểu Toán tử này không có kiểu trả về, có tên là tên của kiểu chuyển đổi và không có tham số Cú pháp operator type_name ( );
- Toán tử chuyển kiểu (5/5) #40 class CNumber { double data; public: CNumber n1(9.7), n2(2.6); CNumber(double f=0.0) { double x=(double)n1; //gọi operator double() data=f; cout<<"x="<<x<<endl; } int y=(int)n2; //gọi operator int() operator double() cout<<"y="<<y<<endl; { return data; } operator int() { return (int)data; } };
- Sự nhập nhằng (ambiguity) (1/) #41 Nhập nhằng là hiện int Sum(int a, int b) { tượng xảy ra khi TBD return a+b; } tìm được ít nhất 02 cách double Sum(double a, double b) { chuyển kiểu return a+b; } int a = 5, b = 7; cout<<Sum(a,b)<<endl; //OK double x = 4.5, y =6.8; cout<<Sum(x,y )<<endl; //OK cout<<Sum(a,x)<<endl; //ambiguity: int Sum(int,int) or //double Sum(double, double)
- Sự nhập nhằng (ambiguity) (2/) #42 Hiện tượng nhập nhằng thường xảy ra khi định nghĩa lớp & chuyển kiểu bằng constructor/ toán tử class CNumber { CNumber n1(5),n2; private: n2 = n1 + 3; //ambiguity int data; double r = 2.5 + n1; //ambiguity public: CNumber(int x=0) CNumber n1(5),n2; { n2 = n1 + CNumber (3); //OK data=x; double r = 2.5 + double(n1); //OK } operator double() { return data/2.0; } friend CNumber operator + (CNumber n1, CNumber n2); };
- Đa năng toán tử > (1/) #43 > là hai toán tử thao tác trên bit số nguyên C++ định nghĩa > dùng các đối tượng thuộc lớp ostream & istream để thực hiện các thao tác xuất/ nhập Lớp ostream định nghĩa toán tử > áp dụng cho các kiểu dữ liệu cơ bản
- Đa năng toán tử > (2/) #44 Dùng tham chiếu ostream đa năng toán tử > để nhập dòng dữ liệu cho lớp đang định nghĩa
- Đa năng toán tử > (3/) #45 class CComplex { private: double real, image; public: CComplex (double r = 0, double i=0) { real = r; image = i; } friend istream& operator >> (istream &is, CComplex &c); friend ostream& operator << (ostream &os, CComplex &c); };
- Đa năng toán tử > (4/) #46 istream& operator >> (istream& is, CComplex& c) { cout >c.real; cout >c.image; return is; } ostream& operator >c; cout<<"So phuc vua nhap:"<<c;
- Q&A #47