Giới thiệu
Cách cài đặt & sử dụng đa năng hoá toán tử
Một số kỹ thuật đa năng hoá toán tử đặc biệt
Đ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ử
47 trang |
Chia sẻ: candy98 | Lượt xem: 1163 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Bài giảng Lập trình hướng đối tượng - Chương 4: Đa năng hóa toán tử - Trần Minh Thái, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Chương 4 Đa năng hoá toán tửTRẦN MINH THÁIEmail: minhthai@itc.edu.vnWebsite: www.minhthai.edu.vn Cập nhật: 10 tháng 02 năm 2015Nội dungGiới thiệuCách cài đặt & sử dụng đa năng hoá toán tửMột số kỹ thuật đa năng hoá toán tử đặc biệtGiới thiệu (1/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)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 friendHàm thành viên của lớp (hàm non-static) có thuộc tính truy xuất publicGiới thiệu (3/3)Cú pháp khi gọiKhai báoHàm thành viênHàm toàn cụcaa#bbaa.operator#(bb)operator#(aa,bb)#aaaa.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/)Không thể định nghĩa toán tử mớiPhầ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_castKhô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/)Không thể thay đổi ý nghĩa của toán tử khi áp dụng các kiểu cài sẵnKhông dùng tham số có giá trị mặc địnhCá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)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ôiToán tử được khai báo là hàm toàn cục hoặc hàm thành viênTham số (2/2)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 đổibool 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 đổiCác toán tử tính toán/ so sánh thường dùng hằng tham chiếuGiá trị trả về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ề boolGiá trị trả về có thể là hằng hoặc tham chiếu tuỳ theo ngữ cảnhVí dụ hàm toán tử thành viên (1/3)class CComplex{ 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 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ử: + - ! ++ -- -> ~ * &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)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)Gồm các toán tử: () [] ++ -- , = -> Toán tử chuyển kiểuToán tử new và deleteToá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)class CVector{ private: int size; int *data; public: CVector(int s = 2); ~CVector(); int & operator[](int i); int & operator()(int i);};CVector::CVector(int s){ size = s; data = new int[size]; for(int i=0;iTruy xuất thành viên dưới dạng con trỏclass CMyClass{ public: int data ; CMyClass * operator ->() { return this; }}CMyClass m ;coutdata;Toán tử phẩy (,)Là toán tử hai ngôiCó giá trị là giá trị của biểu thức cuối cùngclass CMyPoint{ private: int x, y; public: CMyPoint(int a = 0 , int b = 0 ) { x = a; y = b; } CMyPoint operator ,(CMyPoint); };CMyPoint CMyPoint :: operator , (CMyPoint p){ CMyPoint tmp ; tmp.x = p.x ; tmp.y = p.y ; return tmp ;}Toán tử gán (1/2)Phép gán và constructor sao chép chỉ thực hiện sao chép đơn giản (shallow copy)class A{ private: int *data; public: A(int x) { data = new int(x); } ~A() { delete data; } void Print(char *st) { coutPrint("a.");new A(5)aAdata5(instance)A b(10);b.Print("b.");b = *a;b.Print("b.");10Adata(instance)?delete a;b.Print("b."); //runtime erroraĐa năng hoá toán tử gán (1/3)Đa năng hóa toán tử gán chỉ cần thiết khiSao chép có xử lý bên trong (deep copy) – chẳng hạn sử dụng bộ nhớ độngSao 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)class CMyString { char *str; public: CMyString(char *s = "") { str = strdup(s); } CMyString(const CMyString &s) { str = strdup(s.str); } ~CMyString() { free(str); } CMyString & operator = (const CMyString &s); void Output() const { cout Print();coutPrint();delete p1;delete p2;delete x;Đa năng hoá toán tử new & delete (3/3)Hàm thành viênclass CNumber{ int x; public: CNumber(int a=0) { x=a; } void * operator new(size_t size) { coutPrint();delete n;delete x;Toán tử chuyển kiểu (1/5)Có hai toán tử chuyển kiểuNgầ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ểuToán tử chuyển kiểu (2/5)Chuyển kiểu ngầm địnhclass 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)Nếu muốn ngăn chặn chuyển kiểu tự động, dùng từ khoá explicit khi khai báo constructorclass 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)Toán tử chuyển kiểuLà thành viên của lớp cần chuyển kiểuToá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)class CNumber{ double data; public: CNumber(double f=0.0) { data=f; } operator double() { return data; } operator int() { return (int)data; }};CNumber n1(9.7), n2(2.6);double x=(double)n1; //gọi operator double()cout> (1/)> là hai toán tử thao tác trên bit số nguyênC++ đị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ậpLớ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/)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/)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 > (4/)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