C++ OOP từ cơ bản đến nâng cao (Phần 2)

Xin chào các bạn, bài hôm nay chúng ta sẽ tiếp tục tìm hiểu về Constructor trong lập trình hướng đối tượng với C++. Ở bài trước như đã giới thiệu có 3 loại Constructor:
+ Cononstructor mặc định
+ Constructor có tham số
+ Constructor sao chép
Constructor mặc định
+ Không có kiểu trả về
+ Cùng tên với class
+ Phải trong tầm vực Public
Constructor có tham số
+ Có 3 tính chất như trên
+ Có tham số truyền vào
Ta khai báo như sau:
class SampleClass{
   private:
     int paramA, paramB;
    public:
     SampleClass(){ // Hàm khởi tạo mặc định
        paramA=0;
            paramB=0;
}
     SampleClass(int prA,int prB){// Hàm khởi tạo có tham số truyền vào
       paramA=prA;
      paramB=prB;
}
};
Cách gọi (2 cách như sau)
int main(){
    // Cách 1: trực tiếp
    SampleClass c1(5,5);
    // Cách 2: Gián tiếp
    SampleClass c1=SampleClass(5,5);
     system("exit");
     return 0;
}
Constructor sao chép (copy constructor)
Nhưng trước khi đi vào tìm hiểu, chúng ta hãy lướt qua khái niệm "Tham chiếu" là gì trước nhé, tại sao mình lại nói như vậy vì khi sử dụng copy constructor có sử dụng đến khais niệm "Tham chiếu" vì vậy chúng ta sẽ đi tìm hiểu lần lượt nhé
Cách khai báo tham chiếu:
int b=6; // lúc này b được cấp phát bộ nhớ và có giá trị là 6.
int &c=b; // ta nói c là tham chiếu của b hoặc c là nickname của b, sử dụng c,b là như nhau.
Ví dụ sau sử dụng các tham chiếu trong C++:
#include<iostream>
using namespace std;
int main(){
   // khai báo các biến;
   int i;
   double d;
   // Khai báo các biến tham chiếu
   int& r=i;
   double& s=d;
   i=5; 
   cout<<"Gia tri cua i la: "<<i<<endl;
   cout<<"Gia tri cua tham chieu toi i la: "<<r<<endl;
  d=11.7;
   cout<<"Gia tri cua d: "<<d<<endl;
  cout<<"Gia tri cua tham chieu toi d la: "<<s<<endl;
  return 0;
}
Vậy các bạn đã hiểu được khái niệm tham chiếu trong C++ rồi, chúng ta quay lại chủ đề Hàm khởi tạo sao chép nhé.
Ta cùng xem ví dụ sau:
#include<stdio.h>
#include<iostream>
using namespce std;
class ClassA{
   private: 
      int a,b;
    public:
       ClassA(){
      a=0;
      b=1;
}
// truyền vào 2 tham số  
   ClassA(int A,int B){
     a=A;
     b=B;
}
   void increase(){
     a++;
    b++;
}
};
int main(){
   ClassA clA1(2,3), clA2;
   clA2=clA1; // Phép gán bình thường.
system("exit");
 return 0;
}
Ở ví dụ trên ta gán clA2 cho clA1, có nghĩa là nó sẽ tuần tự gán từng giá trị của clA1 qua cho clA2, khi chạy chương trình ta debug sẽ thấy kết quả như hình: 
Đây gọi là phép gán bình thường (mặc định)
Chúng ta có thể tạo ra đối tượng mới giống đối tượng cũ một số đặc điểm, không phải hoàn toàn như phép gán bình thường, hình thức "giống nhau" được định nghĩa theo quan niệm của người lập trình đó là phương trình thiết lập sao chép.
class ClassB{
   private:
       string str;
      int id;
   public:
      ClassB(){}
     ClassB(string STR, int ID){
       str=STR;
       id=ID;
}
// Cú pháp
// Chúng ta sẽ truyền tham chiếu, nếu chuyền tham trị sẽ tạo ra 1 vùng copy
ClassB(const ClassB& clB){
     str=clB.str;
}
};
Chúng ta tiếp tục đến với phần tiếp theo của series này nhé
Hàm phá hủy(Destructor)
+ Destructor được gọi ngay trước khi một đối tượng bị thu hồi.
+ Destructor thường được dùng để thực hiện việc dọn dẹp cần thiết trước khi một đối tượng bị hủy.
+ Một lớp chỉ có duy nhất một Destructor 
+ Phương thức Destructor trùng tên với tên lớp nhưng có dấu "~" đằng trước.
+ Được tự động gọi thực hiện khi đối tượng hết phạm vi sử dụng.
+ Destructor phải có thuộc tính public
Cú pháp:
class ClassB{
  private:
     string str;
     int id;
public:
    classB(){}
    classB(string STR, int ID){
      str=STR;
      id=ID;
}
   ~ClassB(){
    cout<<"Đây là hàm phá hủy";
}
Ví dụ bài toán sử dụng con trỏ, ta dùng hàm phá hủy để giải phóng.
class ClassB{
    private:
    int* p;
    public: 
    ~ClassB(){
         if(p){
     delete p;
    p=nullptr;
 }
}
};
Thành viên( thuộc tính) tĩnh - static data member
Các đặc tính chính:
+ Một bản duy nhất tồn tại trong suốt quá trình chạy của chương trình.
+ Dùng chung cho tất cả các đối tượng của lớp. Bất kể có bao nhiêu đối tượng tạo ra từ class đó.
 + Phải được định nghĩa bên ngoài class vì thành viên tĩnh được lưu trữ riêng biệt, không giống như các thành phần khác của đối tượng.
+ Giá trị khởi tạo =0 và có thể gián giá trị khởi tạo.
Ví dụ minh họa cho các bạn dễ hình dung
#include<stdio.h>
#include<iostream>
using namespace std;
class ClassB{
    private: 
  // khai báo thành phần static
   static int count;
   public:
   classB(){
    count++;
}
   void CountValue(){
    cout<<"Count = "<<count;
}
};
int ClassB::count; // Khởi tại biến static (có thể thiết đặt giá trị mặc định ở đây)
int main(){
   ClassB clB1,clB2;
   system("exit");
   return 0;
}
Khi gọi hàm CountValue() giá trị của biến count sẽ =2;
Thành viên(thuộc tính) tĩnh  - static member fuctions
Các đặc tính chính:
+ Phương thức tĩnh chỉ có thể truy cập đến thành viên tĩnh(thuộc tính hoặc phương thức tĩnh khác)
+ 1 phương thức tĩnh có thể được gọi qua tên class ngay khi không có đối tượng nào của lớp đó tồn tại
Ví dụ minh họa cho các bạn dễ hình dung:
#include<stdio.h>
#include<iostream>
using namespace std;
class ClassB{
   private:
   //Khai báo thành phần static
    static int count;
  public:
     classB(){
      count++;
}
    static int CountValue(){
     return count;
}
};
int ClassB::count;
int main(){
    ClassB clB1,clB2;
   cout<<"Dem: "<<ClassB::CountValue(); // return value =2;    system("exit");
   return 0;
}
Bài này tạm thời chúng ta sẽ dừng tại đây, hẹn gặp các bạn trong bài viết tiếp theo của mình nhé.
Nguồn: https://medium.com/tuanbinhblog/c-oop-từ-cơ-bản-đến-nâng-cao-phần-2-5c3764ef23ae

Nhận xét