Đa năng hóa toán tử trong Lập trình hướng đối tượng (Phần 1) – VOER

ĐA NĂNG HOÁ CÁC TOÁN TỬ HAI NGÔI

Các toán tử hai ngôi được đa năng hóa trong hình 4.5 sau:

Các toán tử hai ngôi được đa năng hóa (Hình 4.5)

Một toán tử hai ngôi có thể được đa năng hóa như là hàm thành viên không tĩnh với một tham số hoặc như một hàm không thành viên với hai tham số (một trong các tham số này phải là hoặc là một đối tượng lớp hoặc là một tham chiếu đến đối tượng lớp).

Ví dụ 4.2: Chúng ta xây dựng lớp số phức với tên lớp là Complex và đa năng hóa các toán tử tính toán + – += -= và các toán tử so sánh == != > >= < <= với các hàm toán tử là các hàm thành viên.


1: #include <iostream.h>
    2: #include <math.h>
    3:
    4: class Complex
    5: {
    6: private: 
    7: double Real, Imaginary;
    8: public: 
    9: Complex(); // Constructor mặc định
    10: Complex(double R,double I);
    11: Complex (const Complex & Z); // Constructor sao chép
    12: Complex (double R); // Constructor chuyển đổi
    13: void Print(); // Hiển thị số phức
    14: // Các toán tử tính toán
    15: Complex operator + (Complex Z);
    16: Complex operator - (Complex Z);
    17: Complex operator += (Complex Z);
    18: Complex operator -= (Complex Z);
    19: // Các toán tử so sánh
    20: int operator == (Complex Z);
    21: int operator != (Complex Z);
    22: int operator > (Complex Z);
    23: int operator >= (Complex Z);
    24: int operator < (Complex Z);
    25: int operator <= (Complex Z);
    26: private: 
    27: double Abs(); // Giá trị tuyệt đối của số phức
    28: };
    29:
    30: Complex::Complex()
    31: {
    32: Real = 0.0;
    33: Imaginary = 0.0;
    34: }
    35:
    36: Complex::Complex(double R,double I)
    37: {
    38: Real = R;
    39: Imaginary = I;
    40: }
    41:
    42: Complex::Complex(const Complex & Z)
    43: {
    44: Real = Z.Real;
    45: Imaginary = Z.Imaginary;
    46: }
    47:
    48: Complex::Complex(double R)
    49: {
    50: Real = R;
    51: Imaginary = 0.0;
    52: }
    53:
    54: void Complex::Print()
    55: {
    56: cout<<'('<<Real<<','<<Imaginary<<')';
    57: }
    58:
    59: Complex Complex::operator + (Complex Z)
    60: {
    61: Complex Tmp;
    62
    63: Tmp.Real = Real + Z.Real;
    64: Tmp.Imaginary = Imaginary + Z.Imaginary;
    65: return Tmp;
    66: }
    67:
    68: Complex Complex::operator - (Complex Z)
    69: {
    70: Complex Tmp;
    71:
    72: Tmp.Real = Real - Z.Real;
    73: Tmp.Imaginary = Imaginary - Z.Imaginary;
    74: return Tmp;
    75: }
    76:
    77: Complex Complex::operator += (Complex Z)
    78: {
    79: Real += Z.Real;
    80: Imaginary += Z.Imaginary;
    81: return *this;
    82: }
    83:
    84: Complex Complex::operator -= (Complex Z)
    85: {
    86: Real -= Z.Real;
    87: Imaginary -= Z.Imaginary;
    88: return *this;
    89: }
    90:
    91: int Complex::operator == (Complex Z)
    92: {
    93: return (Real == Z.Real) && (Imaginary == Z.Imaginary);
    94: }
    95:
    96: int Complex::operator != (Complex Z)
    97: {
    98: return (Real != Z.Real) || (Imaginary != Z.Imaginary);
    99: }
    100:
    101: int Complex::operator > (Complex Z)
    102: {
    103: return Abs() > Z.Abs();
    104: }
    105:
    106: int Complex::operator >= (Complex Z)
    107: {
    108: return Abs() >= Z.Abs();
    109: }
    110:
    111: int Complex::operator < (Complex Z)
    112: {
    113: return Abs() < Z.Abs();
    114: }
    115:
    116: int Complex::operator <= (Complex Z)
    117: {
    118: return Abs() <= Z.Abs();
    119: }
    120:
    121: double Complex::Abs()
    122: {
    123: return sqrt(Real*Real+Imaginary*Imaginary);
    124: }
    125:
    126: int main()
    127: {
    128: Complex X, Y(4.3,8.2), Z(3.3,1.1), T;
    129
    130: cout<<"X: ";
    131: X.Print();
    132: cout<<endl<<"Y: ";
    133: Y.Print();
    134: cout<<endl<<"Z: ";
    135: Z.Print();
    136: cout<<endl<<"T: ";
    137: T.Print();
    138: T=5.3;// Gọi constructor chuyển kiểu
    139: cout<<endl<<endl<<"T = 5.3"<<endl;
    140: cout<<"T: ";
    141: T.Print();
    142: X = Y + Z;
    143: cout<<endl<<endl<<"X = Y + Z: ";
    144: X.Print();
    145: cout<<" = ";
    146: Y.Print();
    147: cout<<" + ";
    148: Z.Print();
    149: X = Y - Z;
    150: cout<<endl<<"X = Y - Z: ";
    151: X.Print();
    152: cout<<" = ";
    153: Y.Print();
    154: cout<<" - ";
    155: Z.Print();
    156: cout<<endl<<endl<<"Y += T i.e ";
    157: Y.Print();
    158: cout<<" += ";
    159: T.Print();
    160: Y += T;
    161: cout<<endl<<"Y: ";
    162: Y.Print();
    163: cout<<endl<<"Z -= T i.e ";
    164: Z.Print();
    165: cout<<" -= ";
    166: T.Print();
    167: Z -= T;
    168: cout<<endl<<"Z: ";
    169: Z.Print();
    170: Complex U(X);// Gọi constructor sao chép
    171: cout<<endl<<endl<<"U: ";
    172: U.Print();
    173: cout<<endl<<endl<<"Evaluating: X==U"<<endl;
    174: if (X==U)
    175: cout<<"They are equal"<<endl;
    176: cout<<"Evaluating: Y!=Z"<<endl;
    177: if (Y!=Z)
    178: cout<<"They are not equal => ";
    179: if (Y>Z)
    180: cout<<"Y>Z";
    181: else
    182: cout<<"Y<Z";
    183: return 0;
    184: }
    

Chúng ta chạy ví dụ 4.2, kết quả ở hình 4.6.

Dòng thứ 10 của chương trình ở ví dụ 4.2: Complex(const Complex &Z);

là một constructor sao chép (copy constructor). Nó khởi động một đối tượng lớp bằng cách tạo một sao chép của một đối tượng lớp đó. Constructor sao chép thực hiện công việc giống như toán tử sao chép nhưng nó có một vai trò đặc biệt. Constructor sao chép chỉ nhận tham số là một tham chiếu chỉ đến đối tượng thuộc chính lớp mà nó được định nghĩa. Các constructor sao chép được dùng mỗi khi một sự sao chép của một đối tượng cần thiết như khi có sự truyền tham số bằng trị, khi trả về một đối tượng từ hàm, hoặc khi khởi động một đối tượng mà được sao chép từ đối tượng khác của cùng lớp. Chẳng hạn:


Complex A(3.5, 4.5);
    Complex B(A); // Gọi constructor sao chép
    Complex C = B; // Gọi constructor sao chép
    …………………
    Complex MyFunc(Complex Z) // Gọi constructor sao chép
    { rZ; // Gọi constructor sao chép }
    


Kết quả của ví dụ 4.2 (Hình 4.6)

Chúng ta chú ý rằng, dấu = trong câu lệnh trên ứng với constructor sao chép chứ không phải là toán tử gán . Nếu chúng ta không định nghĩa constructor sao chép, trình biên dịch tạo ra một constructor sao chép mặc định sẽ sao chép từng thành viên một.

Ở dòng 12 của chương trình ở ví dụ 4.2:

Complex(double R);

là một constructor chuyển đổi (conversion constructor). Constructor này lấy một tham số double và khởi tạo đối tượng Complex mà phần thực bằng giá trị tham số truyền vào và phần ảo bằng 0.0 (từ dòng 48 đến 52). Bất kỳ một constructor nào có tham số đơn có thể được nghĩ như một constructor chuyển đổi. Constructor chuyển đổi sẽ đổi một số thực thành một đối tượng Complex rồi gán cho đối tượng đích Complex. Chẳng hạn:

T = 3.5; // Ngầm định: T = Complex(3.5)

Trình biên dịch tự động dùng constructor chuyển đổi để tạo một đối tượng tạm thời Complex, rồi dùng toán tử gán để gán đối tượng tạm thời này cho đối tượng khác của Complex. Chẳng hạn câu lệnh sau vẫn đúng:

X = Y + 3.5; // Ngầm định: X = Y + Complex(3.5);

Như vậy một constructor chuyển đổi được sử dụng để thực hiện một sự chuyển đổi ngầm định.

Ví dụ 4.3: Lấy lại ví dụ 4.2 nhưng các hàm toán tử +, – và các hàm toán tử so sánh là hàm không thành viên.


#include <iostream.h>
#include <math.h>
class Complex
{
	private:
		double Real,Imaginary;
	public:
		Complex();//Constructor mac dinh
		Complex(double R,double I);
		Complex (const Complex & Z);//Constructor sao chep
		Complex (double R);//Constructor chuyen doi
		void Print();//Hien thi so phuc
		//Cac toan tu tinh toan
		friend Complex operator + (Complex Z1,Complex Z2);
		friend Complex operator - (Complex Z1,Complex Z2);
		Complex operator += (Complex Z);
		Complex operator -= (Complex Z);
		//Cac toan tu so sanh
		friend int operator == (Complex Z1,Complex Z2);
		friend int operator != (Complex Z1,Complex Z2);
		friend int operator > (Complex Z1,Complex Z2);
		friend int operator >= (Complex Z1,Complex Z2);
		friend int operator < (Complex Z1,Complex Z2);
		friend int operator <= (Complex Z1,Complex Z2);
	private:
		double Abs();//Gia tri tuyet doi cua so phuc
};
Complex::Complex()
{
	Real = 0.0;
	Imaginary = 0.0;
}
Complex::Complex(double R,double I)
{
	Real = R;
	Imaginary = I;
}
Complex::Complex(const Complex & Z)
{
	Real = Z.Real;
	Imaginary = Z.Imaginary;
}

Complex::Complex(double R)
{
	Real = R;
	Imaginary = 0.0;
}
void Complex::Print()
{
	cout<<'('<<Real<<','<<Imaginary<<')';
}
Complex operator + (Complex Z1,Complex Z2)
{
	Complex Tmp;
	Tmp.Real = Z1.Real + Z2.Real;
	Tmp.Imaginary = Z1.Imaginary + Z2.Imaginary;
	return Tmp;
}
Complex operator - (Complex Z1,Complex Z2)
{
	Complex Tmp;
	Tmp.Real = Z1.Real - Z2.Real;
	Tmp.Imaginary = Z1.Imaginary - Z2.Imaginary;
	return Tmp;
}
Complex Complex::operator += (Complex Z)
{
	Real += Z.Real;
	Imaginary += Z.Imaginary;
	return *this;
}
Complex Complex::operator -= (Complex Z)
{
	Real -= Z.Real;
	Imaginary -= Z.Imaginary;
	return *this;
}
int operator == (Complex Z1,Complex Z2)
{
	return (Z1.Real == Z2.Real) && (Z1.Imaginary == Z2.Imaginary);
}
int operator != (Complex Z1,Complex Z2)
{
	return (Z1.Real != Z2.Real) || (Z1.Imaginary != Z2.Imaginary);
}
int operator > (Complex Z1,Complex Z2)
{
	return Z1.Abs() > Z2.Abs();
}
int operator >= (Complex Z1,Complex Z2)
{
	return Z1.Abs() >= Z2.Abs();
}
int operator < (Complex Z1,Complex Z2)
{
	return Z1.Abs() < Z2.Abs();
}
int operator <= (Complex Z1,Complex Z2)
{
	return Z1.Abs() <= Z2.Abs();
}
double Complex::Abs()
{
	return sqrt(Real*Real+Imaginary*Imaginary);
}
int main()
{
	Complex X,Y(4.3,8.2),Z(3.3,1.1);
	cout<<"X: ";	  X.Print();
	cout<<endl<<"Y: "; Y.Print();
	cout<<endl<<"Z: "; Z.Print();
	X = Y + 3.6;
	cout<<endl<<endl<<"X = Y + 3.6: ";
	X.Print(); 	cout<<" = ";
	Y.Print(); 	cout<<" + 3.6 ";
	X = 3.6 + Y;	cout<<endl<<"X = 3.6 + Y: ";
	X.Print(); 	cout<<" = 3.6 + ";
	Y.Print(); 	X = 3.8 - Z;
	cout<<endl<<"X = 3.8 - Z: ";
	X.Print(); 	cout<<" = 3.8 - ";
	Z.Print(); 	X = Z - 3.8;
	cout<<endl<<"X = Z - 3.8: ";
	X.Print(); 	cout<<" = ";
	Z.Print(); 	cout<<" - 3.8 ";
	return 0;
}

Chúng ta chạy ví dụ 4.3, kết quả ở hình 4.7


Kết quả của ví dụ 4.3 (Hình 4.7)