C++ toàn tập

Đây là ngôn ngữ rất phổ biến được nhiều người lựa chọn và nó có cơ hội việc làm thu nhập rất cao nếu bạn thông thạo nó. Vì vậy Blog đã viết một loạt bài về C++ với mục đích giúp các bạn tiện tra cứu và học hỏi.

Cơ bản:

STL

  • Stack (ngăn xếp)
  • Vector trong C++
  • Queue (hàng đợi)
  • Deque (hàng đợi hai đầu)
  • Priority queue (hàng đợi ưu tiên)
  • Set (tập hợp)
  • List (danh sách liên kết)
  • Multiset (tập hợp)
  • Lập trình hướng đổi tượng (OOP) trên C++

    Lập trình hướng đối tượng (Object oriented programming) – như cái tên của nó, ta sẽ viết chương trình chứa các đối tượng (object). Lập trình hướng đối tượng nhằm mục đích triển khai các đối tượng thực tế(như nhà, xe,…). The main aim of OOP is to bind together the data and the functions that operates on them so that no other part of code can access this data except that function.
    Let us learn about different characteristics of an Object Oriented Programming language:
    Đối tượng: Objects are basic run-time entities in an object oriented system, objects are instances of a class these are defined user defined data types.
    ex:

    class person
    {
        char name[20];
        int id;
    public:
        void getdetails(){}
    };
    int main()
    {
       person p1; //p1 is a object
    }

    Object take up space in memory and have an associated address like a record in pascal or structure or union in C.

    When a program is executed the objects interact by sending messages to one another.

    Each object contains data and code to manipulate the data. Objects can interact without having to know details of each others data or code, it is sufficient to know the type of message accepted and type of response returned by the objects.

    Class: Class is a blueprint of data and functions or methods. Class does not take any space.

    Syntax for class:

    class class_name
    {
      private:
         //data members and member functions declarations
      public:
         //data members and member functions declarations
      protected:
         //data members and member functions declarations
    };

    Class is a user defined data type like structures and unions in C.

    By default class variables are private but in case of structure it is public. in above example person is a class.

    Đóng gói và trừu tượng hóa dữ liệu: Wrapping up(combing) of data and functions into a single unit is known as encapsulation. The data is not accessible to the outside world and only those functions which are wrapping in the class can access it. This insulation of the data from direct access by the program is called data hiding or information hiding.

    Data abstraction refers to, providing only needed information to the outside world and hiding implementation details. For example, consider a class Complex with public functions as getReal() and getImag(). We may implement the class as an array of size 2 or as two variables. The advantage of abstractions is, we can change implementation at any point, users of Complex class wont’t be affected as out method interface remains same. Had our implementation be public, we would not have been able to change it.

    Kế thừa: inheritance is the process by which objects of one class acquire the properties of objects of another class. It supports the concept of hierarchical classification. Inheritance provides re usability. This means that we can add additional features to an existing class without modifying it.

    Đa hình: polymorphism means ability to take more than one form. An operation may exhibit different behaviors in different instances. The behavior depends upon the types of data used in the operation.
    C++ supports operator overloading and function overloading.
    Operator overloading is the process of making an operator to exhibit different behaviors in different instances is known as operator overloading.
    Function overloading is using a single function name to perform different types of tasks.
    Polymorphism is extensively used in implementing inheritance.

    Dynamic Binding: In dynamic binding, the code to be executed in response to function call is decided at runtime. C++ has virtual functions to support this.

    Message Passing: Objects communicate with one another by sending and receiving information to each other. A message for an object is a request for execution of a procedure and therefore will invoke a function in the receiving object that generates the desired results. Message passing involves specifying the name of the object, the name of the function and the information to be sent.

    Phân biệt tham chiếu và tham trị

    Tham trị

    Tiếng Anh là pass-by-value. Tham trị có nghĩa là chỉ truyền giá trị của biến này cho một biến mới và khi thay đổi biến mới không làm thay đổi biến cũ

    truyen-tham-so

     

    Tham biến

    Tên tiếng anh là pass-by-reference. Truyền tham biến có nghĩa là truyển cho biến mới địa chị ô nhớ y hệt của biến cũ mặc dù tên biến khác. Khi thay đổi biến mới thì cũng làm thay đổi biến cũ. Truyển tham biến còn được hiểu là thêm một nickname mới cho biến cũ.

    tham-tri

    Cài đặt SDL cho CodeBlocks

    Tải về

    • Tải về: https://www.libsdl.org/projects/SDL_image/release/SDL2_image-devel-2.0.3-mingw.tar.gz
    • Giải nén ra thì thấy có 2 thư mục:
      • Bản 32bit: i686-w64-mingw32
      • Bản 64bit: x86_64-w64-mingw32
    • Ở đây ta dùng bản 32 bit (vì CodeBlock đang dùng mingw32),
    • Trong thư mục này có 4 thư mục bin, include, lib, share
    • Thư mục bin chứa SDL2.dll (liên kết khi chạy, copy file này vào thư mục
      mã nguồn project, cùng folder với main.cpp
      )
    • Thư mục include chứa các file .h (như stdio.h) khai báo các hàm của SDL. Cũng coppy vào thư mục project.
    • Thư mục lib chứa các thư viện (mã đối tượng) để liên kết chương trình. Tương tự như trên, cũng copy vào thư mục project

    Cấu hình CodeBlocks

    Settings / Compiler / Linker Settings / Other linker… 

    Gõ thêm vào: -lmingw32 -lSDL2main -lSDL2

    Làm như trên để khi biên dịch chương trình, Codeblocks sẽ biên dịch cả những thứ trong thư viện SDL

    Tiếp theo, chọn tab Search directories / Compilers

    Thêm vào đường dẫn đến thư mục SDL. Ví dụ: e:\myproject\SDL\

    Chuyển sang tab Linker, thêm đường dẫn tới thư mục lib. Ví dụ: e:\myproject\lib

     

    Multiset (tập hợp) trong C++

    Multiset giống như Set nhưng có thể chứa các khóa có giá trị giống nhau.

    Đọc thêm về Set tại: https://yeulaptrinh.pw/938/set-trong-c/

    Khai báo : giống như set.

    Các hàm thành viên:

    Capacity:

    • size : trả về kích thước hiện tại của multiset. ĐPT O(1)
    • empty : true nếu multiset rỗng, và ngược lại. ĐPT O(1).

    Chỉnh sửa:

    • insert : Chèn phần tử vào set. ĐPT O(logN).
    • erase :
      • xóa theo iterator ĐPT O(logN)
      • xóa theo khóa: xóa tất cả các phần tử bằng khóa trong multiset. ĐPT: O(logN) + số phần tử bị xóa.
    • clear : xóa tất cả set. ĐPT O(n).
    • swap : đổi 2 set cho nhau. ĐPT O(n).

    Operations:

    • find : trả về itarator trỏ đến phần tử cần tìm kiếm. Nếu không tìm thấy itarator trỏ về “end” của set. ĐPT O(logN). Dù trong multiset có nhiều phần tử bằng khóa thì nó cũng chỉ iterator đến một phần tử.
    • lower_bound : trả về iterator đến vị trí phần tử bé nhất mà không bé hơn (lớn hơn hoặc bằng) khóa (dĩ nhiên là theo phép so sánh), nếu không tìm thấy trả về vị trí “end” của set. ĐPT O(logN).
    • upper_bound: trả về iterator đến vị trí phần tử bé nhất mà lớn hơn khóa, nếu không tìm thấy trả về vị trí “end” của set.. ĐPT O(logN).
    • count : trả về số lần xuất hiện của khóa trong multiset. ĐPT O(logN) + số phần tử tìm được.

    Chương trình Demo:

    #include <iostream>
    
    #include <set>
    
    using namespace std;
    
    main() {
        multiset <int> s;
    
        multiset <int> :: iterator it;
    
        int i;
    
        for (i=1;i<=5;i++) s.insert(i*10); // s={10,20,30,40,50}
        s.insert(30);    // s={10,20,30,30,40,50}
        cout << s.count(30) << endl;    // In ra 2
        cout << s.count(20) << endl;    // In ra 1
        s.erase(30);    // s={10,20,40,50}
    
        /* Duyet set */
        for (it=s.begin();it!=s.end();it++) {
        cout << *it <<  " ";
        }
    
        //In ra 10 20 40 50 
        cout << endl; system("pause");
    }
    

    Priority queue (hàng đợi ưu tiên) trong C++

    Priority queue là một loại container adaptor, được thiết kế đặc biệt để phần tử ở đầu luôn luôn lớn nhất (theo một quy ước về độ ưu tiên nào đó) so với các phần tử khác.

    Nó giống như một heap, mà ở đây là heap max, tức là phần tử có độ ưu tiên lớn nhất có thể được lấy ra và các phần tử khác được chèn vào bất kì.

    Phép toán so sánh mặc định khi sử dụng priority queue là phép toán less (Xem thêm ở thư viện functional)

    Để sử dụng priority queue một cách hiệu quả, các bạn nên học cách viết hàm so sánh để sử dụng cho linh hoạt cho từng bài toán.

    Khai báo: #include <queue>

    /*Dạng 1 (sử dụng phép toán mặc định là less)*/ 
    priority_queue <int> pq;
    
    /* Dạng 2 (sử dụng phép toán khác) */
    priority_queue <int,vector<int>,greater<int> > q; //phép toán greater
    

    Phép toán khác cũng có thể do người dùng tự định nghĩa. Ví dụ:

    Cách khai báo ở dạng 1 tương đương với:

    /* Dạng sử dụng class so sánh tự định nghĩa */ struct cmp{
    
    bool operator() (int a,int b) {return a<b;}
    
    };
    
    main() {
    
    …
    
    priority_queue <int,vector<int>,cmp > q;
    
    }
    

    Các hàm thành viên:

    • size : trả về kích thước hiện tại của priority queue. ĐPT O(1)
    • empty : true nếu priority queue rỗng, và ngược lại. ĐPT O(1).
    • push : đẩy vào priority queue. ĐPT O(logN).
    • pop: loại bỏ phần tử ở đỉnh priority queue. ĐPT O(logN).
    • top : trả về phần tử ở đỉnh priority queue. ĐPT O(1).

    Chương trình demo:

    #include <iostream>
     
    #include <queue>
     
    #include <vector>
     
    using namespace std;
     
    main() {
     
        priority_queue <int> p;	// p={}
     
        p.push(1);	// p={1}
     
        p.push(5);	// p={1,5}
     
        cout << p.top() << endl; // In ra 5
     
        p.pop();	// p={1}
     
        cout << p.top() << endl; // In ra 1
     
        p.push(9);	// p={1,9}
     
        cout << p.top() << endl; // In ra 9
     
        system("pause");
     
    }

    Chương trình Demo 2:

    #include <iostream>
     
    #include <queue>
     
    #include <vector>
     
    using namespace std;
     
    main() {
        priority_queue < int , vector <int> , greater <int> > p;	// p={}
        p.push(1);     //p={1}
        p.push(5);     //p={1,5}
        cout << p.top() << endl;    //In ra 1
        p.pop();       //p={5}
        cout << p.top() << endl;     //In ra 5
        p.push(9);    //p={5,9}
        cout << p.top() << endl; // In ra 5
        system("pause");
    }

    Chương trình Demo 3:

    #include <iostream>
     
    #include <queue>
     
    #include <vector>
     
    using namespace std;
     
    struct cmp{
        bool operator() (int a,int b) {return a<b;}
    };
     
    main() {
        priority_queue < int , vector <int> , cmp > p;	// p={}
        p.push(1);    //p={1}
        p.push(5);    //p={1,5}
        cout << p.top() << endl;     //In ra 1
        p.pop();    //p={5}
        cout << p.top() << endl;     //In ra 5
        p.push(9);    //p={5,9}
        cout << p.top() << endl; // In ra 5
    system("pause");
    }

    Queue (hàng đợi) trong C++

    Queue là một loại cấu trúc dữ liệu và một loại container adaptor, được thiết kế để hoạt động theo kiểu FIFO (First – in first – out) (vào trước ra trước), tức là một kiểu danh sách mà việc bổ sung được thực hiển ở cuối danh sách và loại bỏ ở đầu danh sách.

    Trong queue, có hai vị trí quan trọng là vị trí đầu danh sách (front), nơi phần tử được lấy ra, và vị trí cuối danh sách (back), nơi phần tử cuối cùng được thêm vào.

    Khai báo: #include <queue>

    Các hàm thành viên:

    • size : trả về kích thước hiện tại của queue. ĐPT O(1).
    • empty : true nếu queue rỗng, và ngược lại. ĐPT O(1).
    • push : đẩy vào cuối queue. ĐPT O(1).
    • pop: loại bỏ phần tử (ở đầu). ĐPT O(1).
    • front : trả về phần tử ở đầu. ĐPT O(1).
    • back: trả về phần tử ở cuối. ĐPT O(1).

    Chương trình demo:

    #include <iostream>
    
    #include <queue>
    
    using namespace std;
    
    queue <int> q;
    
    int i;
    
    main() {
      for (i=1;i<=5;i++) q.push(i);
      // q={1,2,3,4,5}
      q.push(100);
      // q={1,2,3,4,5,100}
      cout << q.front() << endl;
      // In ra 1
      q.pop();
      // q={2,3,4,5,100}
      cout << q.back() << endl;
      // In ra 100
      cout << q.empty() << endl;
      // In ra 0
      cout << q.size() << endl;
      // In ra 5
      system("pause");
    }
    

    Stack (ngăn xếp) trong C++

    Stack là một loại container adaptor, được thiết kế để hoạt động theo kiểu LIFO (Last – in first – out) (vào sau ra trước), tức là một kiểu danh sách mà việc bổ sung và loại bỏ một phần tử được thực hiển ở cuối danh sách. Vị trí cuối cùng của stack gọi là đỉnh (top) của ngăn xếp.

     

    Khai báo: #include <stack>

     

    Các hàm thành viên:

    • size : trả về kích thước hiện tại của stack. ĐPT O(1).
    • empty : true stack nếu rỗng, và ngược lại. ĐPT O(1).
    • push : đẩy phần tử vào stack. ĐPT O(1).
    • pop : loại bỏ phẩn tử ở đỉnh của stack. ĐPT O(1).
    • top : truy cập tới phần tử ở đỉnh stack. ĐPT O(1).

    Chương trình demo:

    #include <iostream>
    
    #include <stack>
    
    using namespace std;
    
    stack <int> s;
    
    int i;
    
    main() {
    
      for (i=1;i<=5;i++) s.push(i); // s={1,2,3,4,5} 
      s.push(100); // s={1,2,3,4,5,100} 
      cout << s.top() << endl; // In ra 100 
      s.pop(); // s={1,2,3,4,5} 
      cout << s.empty() << endl; // In ra 0 
      cout << s.size() << endl; // In ra 5 system("pause");
    
    }