Mình cũng xin gửi lời cảm ơn chân thành đến tác giả của các bài viết được sử dụng.
___________________________________________________________________
Nguồn:
1) C++ How to programming - Paul Deitel Harvey Deitel
2) Cuốn lập trình hướng đối tượng - Phạm Văn Ất
___________________________________________________________________
This post is extracted from "C++ How to programming".
Objective:
IN this post, we'll learn:
1) What operator overloading is and how it simplifies programming.
2) To overload operators for user-defined classes.
3) To overload unary and binary operators.
4) To convert objects from one class to another class.
5) To creat phonenumber, array and Dates classes that demonstrate operator overloading.
6) To use overloaded operators and other features of C++'s string class.
7) To use keyword explicit to prevent the complier from using simgel-argument constructor
_______________________________________________________________________________
I. Fundermentals of Operator Overloading:
C++ programming is a type-sensitive and type-focused process. You can use fundermental types and can define new types. The fundermental types can be used with C++ rich-collection of operators. Operators provide you with a concise notation for expressing manipulations of data of fundermental types.
You can use operators with user-defined types as well. Although C++ doesn't allow new operator to be created, it does allow most existing operators to be overloaded so that, when they're used with objects, they have meaning appropriate to those object.
An operator is overloaded by writting a non-static member function definition or global function definition as you normally would, except that the function name now becomes the keyword operator followed by the symbol for the operator being overloaded. For example, the function name operator+ would be used to overload the addition operator(+). When operators are overloaded as member functions, they must be non-static because they must be called on an object of the class and operate on that object.
To use an operator on class object, that operator must be overloaded- with three exceptions. The assignment operator (=) may be used with every class to perform member-wise assignment of the class's data members- each data member is assigned from the assignment's "source" object to the "target" object. Memberwise assignment is dangerous for classes with pointer members; we'll explicitly overload the assignment operator for such classes. The address(&) and comma(,) operator may also be used with objects of any class without overloading. The address operator returns a pointer to the object. The comma operator avaluates the expression to its left then expression to its right, and returns the value of latter expression. Both of these operators can also be overloaded.
Overloading is specially appropriate for mathematical classes. These often require that a substantial set of operators be overloaded to ensure consistency with the mathematical classes are handle in the real world. For example, it would be unusual to overload only addition for a complex number class, because arithmetic operators are also commonly used with complex numbers.
II. Restrictions on Operator Overloading:
Most of C++'s operators can be overloaded.
Operators that can be overloaded:
+ - * / % ^ & |
~ ! = < > += -= *=
/= %= ^= &= |= <<= >>= >>
<< == != <= >= && || ++
-- ->* , -> [ ] ( ) new delete
new[ ] delete[ ]
Operators that can't be overloaded:
. .* :: ?:
Precedence, Associativity and Number Operand:
The precedence of an operator can't be changed by overloading. This can lead to awkward situations in which an operator is overloaded in a manner for which its fixed precedence is inappropriate. However, parentheses can be used to force the order of evaluation of overloaded operators in a expression.
The associativity of an operator (i.e., whethere the operator is applied right-to-left or left-to-right) cannot be changed by overloading.
It isn't possible to change the "arity" of an operator ( i.e., the number of operands an operator takes): Overloaded unary operators; overloaded binary operators. C++'s only ternary operator (?:) cannot be overloaded. Operators &, *, + and - all have both unary and binary versions; these unary and binary can each be overloaded.
Creating new operators:
It isn't possible to creat new operator; only existing operators can be overloading. Unfortunately, this prevents you from using popular notations like the ** operator used in some other programming languages for exponentiation. [Note: You could overload an existing operator to perform exponentiation.]
Operators for Fundamental Types:
The meaning of how an operator works on objects of fundamental
III. Operator functions as Class Members vs. Global Functions:
//------------------------------------------
Bài viết sau được mình sưu tầm trong cuốn Lập trình hướng đối tượng của tác giả Phạm Văn Ất
//------------------------------------------
CHƯƠNG 6: KHÁI NIỆM VỀ ĐỊNH NGHĨA CHỒNG:
Định nghĩa chồng ( hay còn gọi là sự tải bội hay tái định nghĩa) các hàm là dùng cùng một tên để định nghĩa các hàm khác nhau. Đây là một mở rộng rất có ý nghĩa của C++.
Trong khi C hay một số các ngôn ngữ khác, ta sẽ phải sử dụng nhiều hàm để thực hiện cùng một công việc.
1) Một số ví dụ:
Vi dụ 1:
Chương trình giải bài toán tìm max của một dãy số nguyên và max của một dãy số thực. Trong chương trình sử dụng 6 hàm:
1) Hai hàm dùng để nhập dãy sô nguyên và dãy số thực có tên chung là nhapds.
2) Bốn hàm: Tính max 2 số nguyên, tính max 2 số thực, tính max của dãy số nguyên, tính max của dãy số thực được đặt tên chung là max.
#include<iostream>
#include<stdlib.h>
using namespace std;
void nhapds(int *x, int n);
void nhapds(double *x,int n);
int max(int x, int y);
double max(double x, double y);
int max(int *x, int n);
double max(double *x, int n);
void nhapds(int *x, int n)
{
for(int i =1;i<=n;++i)
{
cout<<endl<<"Phan tu "<<i<<" = "; cin>>x[i];
}
}
void nhapds(double *x, int n)
{
for(int i =1;i<=n;++i)
{
cout<<endl<<"Phan tu "<<i<<" = "; cin>>x[i];
}
}
int max(int x, int y)
{
return (x>y?x:y);
}
double max(double x, double y)
{
return(x>y?x:y);
}
int max(int *x, int n)
{
int s = x[1];
for(int i =2;i<=n;++i)
{
s = max(x[i],s);
}
return s;
}
double max(double *x, int n)
{
double s = x[1];
for(int i =2;i<=n;++i)
{
s = max(x[i],s);
}
return s;
}
int main()
{
int a[20],ni,nd;
double x[20];
cout<<endl<<"So phan tu cua day nguyen = "; cin>>ni;
cout<<endl<<"Nhap day so nguyen: "; nhapds(a,ni);
cout<<endl<<"So phan tu cua day so thuc = ";cin>>nd;
cout<<endl<<"Nhap day so thuc: ";nhapds(x,nd);
cout<<endl<<"Max cua day so nguyen = "<<max(a,ni);
cout<<endl<<"Max cua day so thuc = "<<max(x,nd);
cout<<endl;
system("pause");
return 0;
}
Ví dụ 2: Chương trình sau thực hiện phép nhân ma trận:
D = A*B*C
trong đó A,B là các ma trận vuông, C là ma trận hình chữ nhật.
Trong chương trính có 3 cặp hàm trùng tên để thực hiện 3 nhiệm vụ ( nhưng trên 2 đối tượng khác nhau là ma trận vuông và chữ nhật): Nhập ma trận, nhân ma trận và in ma trận.
#include<iostream>
#include<iomanip>
#include<stdlib.h>
using namespace std;
typedef int MT[20][20];
void nhapmt(MT a, const char *ten, int m, int n);
void inmt(MT a, const char *ten, int m, int n);
void nhanmt(MT a, MT b, MT c, int m,int n, int p);
void nhapmt(MT a, const char *ten, int n);
void inmt(MT a, const char *ten, int n);
void nhanmt(MT a, MT b,MT c ,int n);
void nhapmt(MT a, const char *ten, int m, int n)
{
int i,j;
for(i =1;i<=m;++i)
for(j=1;j<=n;++j)
{
cout<<endl<<"Nhap "<<ten<<"["<<i<<"]["<<j<<"] = " ; cin>>a[i][j];
}
}
void nhapmt(MT a, const char *ten, int n)
{
nhapmt(a,ten,n,n);
}
void inmt(MT a, const char *ten, int m, int n)
{
int i,j;
cout<<endl<<"Ma tran: "<<ten;
for(i=1;i<=m;++i)
{
cout<<endl;
for(j=1;j<=n;++j)
cout<<setw(6)<<a[i][j];
}
}
void inmt(MT a, const char *ten, int n)
{
inmt(a,ten,n,n);
}
void nhanmt(MT a, MT b, MT c, int m, int n, int p)
{
int i,j,k;
for(i=1;i<=m;++i)
for(j=1;j<=p;++j)
{
c[i][j] = 0;
for(k=1;k<=n;++k)c[i][j] += a[i][k]*b[k][i];
}
}
void nhanmt(MT a, MT b, MT c, int n)
{
nhanmt(a,b,c,n,n,n);
}
int main()
{
MT a,b,c,d; // d = abc
MT u;
nhapmt(a,"A",2);
nhapmt(b,"B",2);
nhapmt(c,"C",2,3);
nhanmt(a,b,u,2);
nhanmt(u,c,d,2,2,3);
inmt(a,"A",2);
inmt(b,"B",2);
inmt(u,"U = A*B ",2);
inmt(c,"C",2,3);
inmt(d,"D = U*C",2,3);
system("pause");
return 0;
}
Bài 7: Định nghĩa chồng toán tử
1) Các phép toán trong C và C++:
Trong C và C++ có khá nhiều các phép toán dùng để thực hiện các thao tác trên các kiểu dữ liệu chuẩn. Ví dụ các phép số học: + - * /áp dụng cho các kiểu dữ liệu nguyên, thực. Phép lấy phần dư % áp dụng với kiểu nguyên.
2) Cách định nghĩa chồng các toán tử:
a) Tên hàn toán tử:
Gồm từ khóa operator và tên phép gán, ví dụ:
operator+ (Định nghĩa chồng phép +)
operator-(định nghĩa chồng phép -)
b) Với các phép toán có 2 toán hạng, thì hàm toán tử cần có 2 đối. Đối thứ nhất ứng với toán hạng thứ nhất, đối thứ hai ứng với toán hạng thứ 2. Do vậy, với các phép toán không giao hoán (như phép -) thì thứ tự đối là rất quan trọng.
Ví dụ: Các hàm toán tử cộng, trừ phân số được khai báo như sau:
struct PS
{
int a; //Tu so
int b; //Mau so
};
PS operator+(PS p1, PS p2); //p1+p2
PS operator-(PS p1, PS p2); //p1-p2
PS operator*(PS p1, PS p2); //p1*p2
PS operator/(PS p1, PS p2);//p1/p2
b) Với các phép toán có một toán hạng:
Thì hàm toán tử có một đối số. Ví dụ hàm toán tử đổi dấu ma trận ( Đổi dấu tất cả các phần tử của ma trận) được khai báo như sau:
struct MT
{
double a[20][20]; //Mang chua cac phan tu cua ma tran
int m; //So hang ma tran
int n;//So cot ma tran
}
MT operator-(MT x);
7.3.3. Thân của hàm toán tử: Viết như thân của hàm thông thường. Ví dụ: hàm đổi dấu ma trận có thẻ định nghĩa như sau:
struct MT
{
double a[20][20]; //Mang chua cac phan tu cua ma tran
int m; //So hang
int n; //So cot
}
MT operator-(MT x)
{
MT y;
int i,j;
for(i=1;i<m;++i)
for(j=1;j<=n;++j)
y[i][j] = -x[i][j];
return y;
}
7.4.Cách dùng các hàm toán tử:
Có 2 cách dùng:
Cách 1: Dùng như một hàm thông thường bằng cách viết lời gọi:
Ví dụ:
PS p,q,u,v;
u = operator+(p,q); // u = p+q
v = operator-(p,q); // v = p-q
Ví dụ:
PS p,q,u,v;Chú ý:
u = p+q;
v = p-q;
Khi dùng các hàm toán tử như phép toán của C++, ta có thể kết hợp nhiều phép toán để viết các công thức phức tạp. Cũng cho phép sử dụng dấu ngoặc trong để quy định thứ tự thực hiện phép tính vẫn tuân theo các quy tắc ban đầu của C++. Chẳng hạn phép * và / có thứ tự cao hơn phép + và -
BÀI 8: CÁC VÍ DỤ VỀ ĐỊNH NGHĨA CHỒNG TOÁN TỬ
Ví dụ 1: Trong ví dụ này ngoài việc sử dụng các hàm toán tử để thực hiện 4 phép tính trên phân số, còn định nghĩa chồng toán tử các phép toán << và >> để xuất và nhập phân số:
Hàm operator<< có 2 đối số kiểu ostream& và PS(phân số). Hàm trả về giá trị kiểu ostream&. Hàm được khai báo như sau:
ostream& operator<<(ostream& os, PS p);Tương tự hàm operator>> được khai báo như sau:
istream& operator>>(istream& is, PS &p);Dưới đây sẽ chỉ ra cách xây dựng và sử dụng các hàm toán tử. Chúng ta cũng sẽ thấy việc sử dụng các hàm toán tử rất tự nhiên, ngắn gọn và tiện lợi.
**
**
0 comments:
Post a Comment