C++ Programming Language 14

Ví dụ về nạp chồng toán tử trong C++

Nạp chồng toán tử một ngôi

Toán tử một ngôi (unary) trong C++ hoạt động trên một toán hạng đơn, toán tử một ngôi có thể:

  • Nạp chồng toán tử tăng (++) và toán tử giảm (–) trong C++
  • Toán tử một ngôi (-) trong C++
  • Toán tử logic phủ định (!) trong C++

Toán tử một ngôi hoạt động trên đối tượng mà chúng gọi, và thường xuất hiện bên trái đối tượng, dạng như: !obj, -obj, và ++obj, nhưng đôi khi chúng có thể sử dụng như là hậu tố giống như obj++ hoặc obj–.

Ví dụ về toán tử một ngôi (unary), toán tử (-) được nạp chồng bằng cách sử dụng tiền tố cũng như hậu tố:

#include <iostream>
using namespace std;

class KhoangCach {
  private:
      int met; 
      int centimet;

  public:
      // khai bao cac constructor
      KhoangCach() {
      met = 0;
      centimet = 0;
      }

  KhoangCach(int m, int c) {
      met = m;
      centimet = c;
      }

    // phuong thuc de hien thi khoang cach
    void hienthiKC() {
        cout << "Khoang cach bang m la: " << met << endl;
        cout << "Khoang cach bang cm la: " << centimet << endl;
        cout << "\n================================\n" << endl;
    }

    // nap chong toan tu (-)
    KhoangCach operator- () {
        met = -met;
        centimet = -centimet;

        return KhoangCach(met, centimet);
    }
};

int main() {
    KhoangCach K1(20, 6), K2(-6, 15);

    -K1;            // ap dung su phu dinh
    K1.hienthiKC(); // hien thi K1

    -K2;            // ap dung su phu dinh
    K2.hienthiKC(); // hien thi K2

    return 0;
}

Kết quả:

Nạp chồng toán tử nhị phân

Các toán tử nhị phân trong C++ nhận hai tham số.

Ví dụ về cách toán tử cộng (+), toán tử trừ (-) và toán tử chia (/) có thể được nạp chồng trong C++ như sau:

#include <iostream>
using namespace std;

class Box {
    double chieudai;  // Chieu dai cua mot box
    double chieurong; // Chieu rong cua mot box
    double chieucao;  // Chieu cao cua mot box

  public:
    double tinhTheTich(void) {
        return chieudai * chieurong * chieucao;
    }

    void setChieuDai( double dai ) {
        chieudai = dai;
    }

    void setChieuRong( double rong ) {
        chieurong = rong;
    }

    void setChieuCao( double cao ) {
        chieucao = cao;
    }

    // Nap chong toan tu + de cong hai doi tuong Box.
    Box operator+(const Box& b) {
        Box box;
        box.chieudai = this->chieudai + b.chieudai;
        box.chieurong = this->chieurong + b.chieurong;
        box.chieucao = this->chieucao + b.chieucao;

        return box;
    }
};

int main( ) {
    Box Box1;               // Khai bao Box1 la cua kieu Box
    Box Box2;               // Khai bao Box2 la cua kieu Box
    Box Box3;               // Khai bao Box3 la cua kieu Box

    double thetich = 0.0;   // Luu giu the tich cua mot box tai day

    // thong tin chi tiet cua box 1
    Box1.setChieuDai(3.0);
    Box1.setChieuRong(4.0);
    Box1.setChieuCao(5.0);

    // thong tin chi tiet cua box 2
    Box2.setChieuDai(6.0);
    Box2.setChieuRong(7.0);
    Box2.setChieuCao(8.0);

    // the tich cua box 1
    thetich = Box1.tinhTheTich();
    cout << "The tich cua Box1 : " << thetich << endl;

    // the tich cua box 2
    thetich = Box2.tinhTheTich();
    cout << "The tich cua Box2 : " << thetich << endl;

    // Cong hai doi tuong:
    Box3 = Box1 + Box2;

    // the tich cua box 3
    thetich = Box3.tinhTheTich();
    cout << "The tich cua Box3 : " << thetich << endl;

    return 0;
}

Kết quả:

Nạp chồng toán tử quan hệ

Có nhiều toán tử quan hệ đa dạng được hỗ trợ bởi C++, ví dụ như: (<, >, <=, >=, ==, …) mà có thể được sử dụng để so sánh các kiểu dữ liệu có sẵn trong C++.

Bạn có thể nạp chồng bất kỳ toán tử quan hệ nào, mà có thể được sử dụng để so sánh các đối tượng của một lớp.

Ví dụ sau giải thích cách toán tử < trong C++ có thể được nạp chồng và theo cách tương tự, bạn có thể nạp chồng các toán tử quan hệ khác trong C++:

#include <iostream>
using namespace std;

class KhoangCach {
  private:
    int met; 
    int centimet;

  public:
    // phan khai bao cac constructor can thiet
    KhoangCach() {
        met = 0;
        centimet = 0;
    }

    KhoangCach(int m, int c) {
        met = m;
        centimet = c;
    }

    // nap chong toan tu <
    bool operator <(const KhoangCach& k) {
        if(met < k.met) {
            return true;
        }
        if(met == k.met && centimet < k.centimet) {
            return true;
        }

        return false;
    }
};

int main() {
    KhoangCach K1(23, 15), K2(17, 46);
  
    if( K1 < K2 ) {
        cout << "K1 ngan hon K2 " << endl;
    }
    else {
        cout << "K2 ngan hon K1 " << endl;
    }

    return 0;
}

Kết quả:

Nạp chồng toán tử Input / Output

C++ là có thể input và output các kiểu dữ liệu có sẵn bởi sử dụng toán tử trích luồng >> và toán tử chèn luồng <<. Các toán tử trích luồng và chèn luồng cũng có thể được nạp chồng để thực hiện input và output cho các kiểu tự định nghĩa (user-defined).

Ở đây, nó là quan trọng để tạo một hàm nạp chồng toán tử một friend của lớp, bởi vì nó sẽ được gọi mà không tạo một đối tượng.

Ví dụ sau giải thích cách nạp chồng toán tử trích luồng >> và toán tử chèn luồng << trong C++:

#include <iostream>
using namespace std;

class KhoangCach {
  private:
    int met; 
    int centimet; 
		
  public:
    // phan khai bao cac constructor can thiet
    KhoangCach() {
        met = 0;
        centimet = 0;
    }
		
    KhoangCach(int m, int c) {
        met = m;
        centimet = c;
    }

    friend ostream &operator<<( ostream &output, const KhoangCach &K ) { 
        output << "\nDo dai bang m la: " << K.met << "\nVa do dai bang cm la: " << K.centimet;
        return output; 
    }

    friend istream &operator>>( istream  &input, KhoangCach &K ) { 
        input >> K.met >> K.centimet;
        return input; 
    }
};

int main() {
    KhoangCach K1(23, 14), K2(14, 35), K3;
    cout << "Nhap gia tri cua doi tuong K3: " << endl;
    cin >> K3;
    cout << "Khoang cach dau tien: " << K1 << endl;
    cout << "\n==========================\n" << endl;
    cout << "Khoang cach thu hai: " << K2 << endl;
    cout << "\n==========================\n" << endl;
    cout << "Khoang cach thu ba: " << K3 << endl;
    
    return 0;
}

Kết quả:

Nạp chồng toán tử ++ và —

Các toán tử tăng (++) và toán tử giảm (–) là hai toán tử một ngôi quan trọng có sẵn trong C++.

Ví dụ sau minh họa cách nạp chồng toán tử tăng (++) với sự sử dụng của tiền tố cũng như hậu tố. Tương tự, bạn cũng có thể nạp chồng toán tử giảm (–) trong C++:

#include <iostream>
using namespace std;
 
class ThoiGian {
  private:
      int gio;    // tu 0 toi 23
      int phut;   // tu 0 toi 59
  public:
      // phan khai bao cac constructor can thiet
      ThoiGian() {
          gio = 0;
          phut = 0;
      }
	  
      ThoiGian(int h, int m) {
          gio = h;
          phut = m;
      }

      // phuong thuc de hien thi thoi gian
      void hienthiTG() {
          cout << "Gio: " << gio << " Phut: " << phut << endl;
          cout << "-----------------------" << endl;
      }

      // nap chong toan tu ++ (tien to)
      ThoiGian operator++ ()  {
          ++phut;          // tang doi tuong nay
          if(phut >= 60)  {
              ++gio;
              phut -= 60;
          }
          return ThoiGian(gio, phut);
      }

      // nap chong toan tu ++ (hau to)
      ThoiGian operator++( int ) {
          // luu giu gia tri ban dau
          ThoiGian T(gio, phut);

          // tang doi tuong nay
          ++phut;
          if(phut >= 60) {
              ++gio;
              phut -= 60;
          }

          // tra ve gia tri
          return T; 
      }
};

int main() {
    ThoiGian T1(6, 59), T2(19,24);
 
    ++T1;            // tang T1
    T1.hienthiTG();  // hien thi T1
    ++T1;            // tang T1 mot lan lua
    T1.hienthiTG();  // hien thi T1
 
    T2++;            // tang T2
    T2.hienthiTG();  // hien thi T2
    T2++;            // tang T2 mot lan lua
    T2.hienthiTG();  // hien thi T2
    return 0;
}

Kết quả:

Nạp chồng toán tử gán

Bạn có thể nạp chồng toán tử gán (=) như khi bạn có thể với các toán tử khác trong C++ và nó có thể được sử dụng để tạo một đối tượng giống như copy constructor.

Ví dụ sau minh họa cách nạp chồng toán tử gán trong C++:

#include <iostream>
using namespace std;

class KhoangCach {
  private:
    int met; 
    int centimet;

  public:
    // phan khai bao cac constructor can thiet
    KhoangCach() {
        met = 0;
        centimet = 0;
    }

    KhoangCach(int m, int c) {
        met = m;
        centimet = c;
    }

    void operator=(const KhoangCach &K ) { 
        met = K.met;
        centimet = K.centimet;
    }

    // phuong thuc de hien thi khoang cach
    void hienthiKC() {
        cout << "\nDo dai bang m la: " << met <<  "\nVa do dai bang cm la: " <<  centimet << endl;
    }
};

int main() {
    KhoangCach K1(23, 16), K2(15, 46);
    cout << "Khoang cach dau tien: "; 
    K1.hienthiKC();
    cout << "\n-------------------\n";
    cout << "Khoang cach thu hai:"; 
    K2.hienthiKC();
    // su dung toan tu gan
    K1 = K2;
    cout << "\n-------------------\n";
    cout << "Khoang cach dau tien: "; 
    K1.hienthiKC();

    return 0;
}

Kết quả:

Nạp chồng toán tử gọi hàm

Toán tử gọi hàm () trong C++ có thể được nạp chồng cho các đối tượng của kiểu lớp. Khi bạn nạp chồng (), bạn đang không tạo một cách mới để gọi một hàm. Đúng hơn là, bạn đang tạo một hàm toán tử mà có thể được truyền số tham số tùy ý.

Ví dụ sau minh họa cách nạp chồng toán tử gọi hàm () trong C++:

#include <iostream>
using namespace std;

class KhoangCach {
  private:
    int met; 
    int centimet;

  public:
    // phan khai bao cac constructor can thiet
    KhoangCach() {
        met = 0;
    centimet = 0;
    }
	
    KhoangCach(int m, int c) {
        met = m;
        centimet = c;
    }

    // nap chong toan tu goi ham ()
    KhoangCach operator()(int x, int y, int z) {
        KhoangCach K;

        // bay gio, dat phep tinh bat ky
        K.met = x + y + 5;
        K.centimet = y - z + 20 ;

        return K;
    }
	
    // Phuong thuc de hien thi khoang cach
    void hienthiKC() {
        cout << "\nDo dai bang m la: " << met <<  "\nVa do dai bang cm la: " <<  centimet << endl;
    }
};

int main() {
    KhoangCach K1(24, 36), K2;
    cout << "Khoang cach dau tien la: "; 
    K1.hienthiKC();
    K2 = K1(15, 15, 15); // trieu hoi toan tu ()
    cout << "\n--------------------------\n"; 
    cout << "Khoang cach thu hai la: "; 
    K2.hienthiKC();
	
    return 0;
}

Kết quả:

Nạp chồng toán tử subscript[]

Toán tử subscript [] trong C++ thường được sử dụng để truy cập các phần tử mảng. Toán tử này có thể được nạp chồng để nâng cao tính năng đang tồn tại về mảng trong C++ (do vậy, có thể gọi là toán tử chỉ số mảng).

Ví dụ sau minh họa cách nạp chồng toán tử subscript [] trong C++:

#include <iostream>
using namespace std;

const int KICHCO = 15;
class ViDuMang {
  private:
    int mang[KICHCO];
	
  public:
    ViDuMang() {
        register int i;
        for(i = 0; i < KICHCO; i++) {
            mang[i] = i;
        }
    }
	
    int &operator[](int i) {
    if( i > KICHCO ) {
        cout << "\n======================\n" <<endl;
        cout << "Chi muc vuot gioi han!!" <<endl; 
		
        // Tra ve phan tu dau tien.
        return mang[0];
    }

    return mang[i];
    }
};

int main() {
    ViDuMang V;

    cout << "Gia tri cua V[3] la: " << V[3] <<endl;
    cout << "Gia tri cua V[6] la: " << V[6]<<endl;
    cout << "Gia tri cua V[16] la: " << V[16]<<endl;

    return 0;
}

Kết quả:

Nạp chồng toán tử truy cập thành viên lớp (->)

Toán tử truy cập thành viên lớp (->) có thể được nạp chồng, nhưng nó khá là phức tạp. Nó được định nghĩa để cung cấp một kiểu lớp một hành vi “pointer-like”. Toán tử -> phải là một hàm thành viên. Nếu được sử dụng, kiểu trả về của nó phải là một con trỏ hoặc một đối tượng của một lớp để bạn có thể áp dụng.

Toán tử -> thường được sử dụng kết hợp với toán tử * để triển khai “smart pointer”. Những con trỏ này là các đối tượng mà vận hành như các con trỏ thông thường, ngoại trừ việc chúng thực hiện các tác vụ khi bạn truy cập một đối tượng thông qua chúng, ví dụ: xóa đối tượng tự động hoặc khi con trỏ bị hủy hoặc khi con trỏ được sử dụng để trỏ tới đối tượng khác.

Toán tử -> có thể được định nghĩa như là một toán tử hậu tố một ngôi

class Ptr {

//…

X * operator->();

};

Các đối tượng của lớp Ptr có thể được sử dụng để truy cập các thành viên của lớp X ở trên theo phương thức giống như cách các con trỏ được sử dụng. Ví dụ:

void f(Ptr p ) {

p->m = 10 ; // la tuong tu (p.operator->())->m = 10

}

Lệnh p->m được thông dịch thành (p.operator->())->m. Sử dụng cùng khái niệm trên, ví dụ sau sẽ giải thích cách một toán tử truy cập lớp -> trong C++ có thể được nạp chồng

#include <iostream>
#include <vector>
using namespace std;

// gia su co mot lop example sau.
class example {
    static int i, j;

  public:
    // cac smart pointer de hien thi
    void f() const { cout << i++ << endl; }
    void g() const { cout << j++ << endl; }
    void h() const { cout << "--------" << endl; }
};

// phan dinh nghia cac thanh vien Static:
int example::i = 4;
int example::j = 15;

// Trien khai mot container cho lop tren
class VJContainer {
    vector <example*> a;
  public:
    void add(example* vj) {
        a.push_back(vj);  // goi phuong thuc chuan cua vector.
    }
    friend class SmartPointer;
};

// trien khai smart pointer de truy cap thanh vien cua lop example.
class SmartPointer {
    VJContainer vc;
    int index;
  public:
    SmartPointer(VJContainer& vjc) {
        vc = vjc;
        index = 0;
    }

    // tra ve gia tri de chi phan cuoi cua danh sach:
    bool operator++() // phien ban toan tu ++ (tien to) {
        if(index >= vc.a.size()) return false;
        if(vc.a[++index] == 0) return false;
        return true;
    }

    bool operator++(int) // phien ban toan tu ++ (hau to) {
        return operator++();
    }

    // nap chong operator->
    example* operator->() const {
        if(!vc.a[index]) {
            cout << "Gia tri 0!!";
            return (example*)0;
        }

        return vc.a[index];
    }
};

int main() {
   const int sz = 5; // so vong lap la 5 (ban thiet lap gia tri khac de xem ket qua)
   example o[sz];
   VJContainer vc;
   for(int i = 0; i < sz; i++) {
       vc.add(&o[i]);
   }

   SmartPointer sp(vc); // tao mot iterator
   do {
       sp->f(); // goi smart pointer
       sp->g();
       sp->h();
   } while(sp++);

   return 0;
}

Kết quả: