Tìm hiểu về lập trình hướng đối tượng (OOP) trong C++

Tìm hiểu về lập trình hướng đối tượng (OOP) trong C++
  1. Khái niệm

Ở những chương trình code bình thường, code của chúng ta như một vector vậy, chúng chỉ là một dãy các dòng lệnh sẽ được chạy tuần tự từ đầu đến cuối. Ngoại lệ là các hàm và dữ liệu sẽ được tách khỏi vector đó và có thể gọi chúng giữa vector để tạo nên kết quả. 

Vậy OOP – Lập trình hướng đối tượng là gì? Nếu nhìn vào cuộc sống thực tế, tất cả thứ bạn thấy xung quanh đều là các đối tượng (Object) , object sẽ luôn có 2 thành phần chính

  • Các đặc tính của chúng. (VD: cân nặng, chiều cao, kích cỡ, hình dáng, màu sắc, …)
  • Các “hành động” chúng có thể bị tương tác hoặc có thể tương tác (Quyển sách bị “mở”, người “đi”, …) (Hàm)

Lập trình hướng đối tượng cho chúng ta khả năng tạo ra các đối tượng liên kết chặt chẽ với nhau và hoạt động như những khối hộp có thể sử dụng lại

VD: Bạn cần tạo một con game thế giới mở, người chơi có thể đi lại trong thế giới.

VD bạn cần tạo ra một ngôi nhà, ngôi nhà được cấu thành từ : bức tường, vật gia dụng, sơn, …. Bạn không thể mỗi nơi lại gọi hết các bức tường, vật gia dụng, sơn, … khác nhau ra, mà chúng ta sẽ có một Lớp – Ngôi nhà chứa tất cả đặc tính chúng ta cần như màu sắc, kích cỡ, và các thuộc tính này sẽ khác nhau mỗi nơi, để có thể sử dụng lại

  1. Class và Object
QnfLA2cHVptrlxRXBNmlIRvhDPfa9g3LJ7Icf52JGEbiWeNTssv5re3wrUvRYHv128YolvasaDupKZIpM2dawUJRL4BYZhjRDOPfsm8W6o K8mCChFTmvwVXFAkAW9kM3wbZ00WKSs44kmxx Z2MQA - quochung.cyou PTIT

Class là một lớp chứa các thuộc tính, chức năng. và Object – đối tượng là một vật thể được tạo ra từ một lớp Class đó.

struct NgayThang { int nam {}; int thang {}; int ngay {}; };

Đây là một lớp ngày tháng có 3 thuộc tính : ngày tháng năm, các lớp bây giờ sẽ là những thời gian khác nhau trong năm

NgayThang tet = 1/1/2022

NgayThang valentine = 4/2/2022

Con trỏ this?

YfOfxemnNCJM U7b Yge4QXCQUUUCabvTcImwuSqgTkCWfCyJLuGjJIhPkvAO48o9371OKjEEfuJ2Hrf 2EhREa5riQ8tLi1bYv5CM2pn2SKkMz8qlUiLHMbM6pKc7G8f3tP5rjSKqSElqP VnQmgw - quochung.cyou PTIT

This là một con trỏ cho phép chúng ta truy cập các thành phần, đặc tính của class

Ví dụ ta đang xây dựng một mạng xã hội với Class, và có một lớp NguoiDung

struct NguoiDung { int taikhoan {}; int matkhau {};};

Ta không thể cho phép người sử dụng khác in ra mật khẩu, tài khoản của một người dùng bất kì

cout << NguoiDung.matkhau;

=> Không cho phép truy cập các phần tử bí mật.

Nhưng ta vẫn cần cho phép người dùng có thể lấy ra mật khẩu khi đăng nhập, đăng xuất, quên mật khẩu, … nhưng mà lại không thể truy cập các phần tử bí mật.

NguoiDung endcontest;

cout << endcontest.matkhau; -> Không được

endcontest.dangnhap(); 

// nhưng 

void NguoiDung::dangnhap() const {

string matkhau;

cin >> matkhau;

if (matkhau == this.matkhau) cout << “dang nhap”;

  }

Ta đã ứng dụng con trỏ this để gọi ra mật khẩu, trong khi không thể truy cập trực tiếp.

  1. Các đặc tính của OOP
zFX7J35Q1qtmDc7ENbJQ sljjPTf OdxuVcBYz txJxSapajdZTKxd zjMqbk eSITIhTkXkPzTddedDEJYjwOqY3L7MzAC0EzYVR K pu5gs 6WB6kFp VY6 pUqJTN6e1SHgy9nSpfSlG B f 3w - quochung.cyou PTIT

Tính đóng gói (Encapsulation):

(Điều này giống ví dụ về this bên trên)

uDfzeGc8RtonzgEmfpW8wSiPti960aXK8MqMW20 JdUpkgY8bd6wKWH5pAZvstXzAO0MSw5eI88n0f4Tmp4I0oCcRL1LuVw1zcFkZRgp0erj9uCbactkaeHUdgT5F zugvRBjYkJomiB9iVW8O0CFw - quochung.cyou PTIT

Là cách để che dấu những tính chất xử lý bên trong của đối tượng, những đối tượng khác không thể tác động trực tiếp làm thay đổi trạng thái  chỉ có thể tác động thông qua các method public của đối tượng đó. 

xem cách thể hiện bằng code dưới đây : class hinhchunhat

WDgadreoPMjdoiA fJXqTXumUn n4THY3sxy9bO9OLDk02OUQeVzS R3F5ok9fgfIzO91h13jtpKWutcI Twqy o0oi4q tTjHlTOGK8ZZ4vzPr8FTthuHkPOi1Z3blw2lOzd iEyIqt - quochung.cyou PTIT
  • height và width ở đây chính là các tính chất (properties) của đối  tượng class hinhchunhat
  • tinhdientich() là method được public nhằm mục đích tương tác với các đối tượng khác. Tạo một class Program với method static để run, xem cách tương tác và thay đổi tính chất  của đối tượng thông qua các method public như nào:

Ta thấy ta sẽ không thể truy cập các thuộc tính height, width. Nhưng vẫn có thể sử dụng các hàm/method để truy cập chúng. 

Tính kế thừa (Inheritance):

Là kỹ thuật cho phép kế thừa lại những tính năng mà một đối tượng khác đã có, giúp tránh việc code lặp dư thừa mà chỉ xử lý công việc tương tự.

  • Kế thừa một cấp (Single level Inheritance): Với một class cha và một class con
Fk5F2xvm2TUt9lsJVVZawNnHWfP1nBPCS2XP5df9VDBlNUJ5VPt8N9z0CABzluYOHGCjczlJyq0KDQ7CE89dqLMZZfFdtrPHYYV2W7 55zGaF38cfyDwX2o72xjXZbxYVk2U - quochung.cyou PTIT

Ví dụ ta có một class đồ điện tử, chúng có các thuộc tính như: số vi mạch, lượng điện sử dụng, hiệu điện thế, cường độ dòng điện ,…. Các thiết bị như điện thoại, tai nghe, … vẫn dùng chúng, nhưng lại có thêm một số thuộc tính riêng khác, nên thay vì phải tạo lại tất cả thuộc tính đó cho từng class điện thoại, tai nghe mới. Ta sẽ gọi Điện thoạilớp kế thừa của đồ điện tử, và thừa hưởng mọi thuộc tính, chức năng của đồ điện tử.

Tính đa hình (Polymorphism):

Là một đối tượng thuộc các lớp khác nhau có thể hiểu cùng một thông điệp theo cách khác nhau.

Ví dụ đa hình trong thực tế: Mình có 2 con vật: chó, mèo hai con vật này khi nhận được mệnh lệnh  là “hãy kêu” thì chó kêu “gâu gâu”,  mèo kêu “meo meo”.

Ví dụ trên cả 2 con vật đều hiểu chung một thông điệp “hãy kêu” và thực hiện theo cách riêng của chúng.

Tính trừu tượng (Abstraction):

Abstraction (Tính trừu tượng) là một khả năng mà chương trình có thể bỏ qua sự phức tạp bằng cách tập trung vào cốt lõi của thông tin cần xử lý.

Điều đó có nghĩa, bạn có thể xử lý một đối tượng bằng cách gọi tên một phương thức và thu về kết quả xử lý, mà không cần biết làm cách nào đối tượng đó được các thao tác trong class.

Ví dụ: bạn có thể nấu cơm bằng nồi cơm điện bằng cách rất đơn giản là ấn công tắc nấu, mà không cần biết là bên trong cái nồi cơm điện đó đã làm thế nào mà gạo có thể nấu thành cơm.

  1.  Nhãn phạm vi

Nhãn public

  • Từ khóa public được dùng để tạo các thành phần “public – công khai” (Cho dữ liệu hoặc hàm) 
  • Các thành phần được tạo public có thể truy cập từ bất cứ chỗ nào trong phần mềm

Nhãn private

  • Từ khóa public được dùng để tạo các thành phần “private – bí mật” (Cho dữ liệu hoặc hàm) 
  • Các phần tử private chỉ có thể truy cập trong class hoặc class friend

Nhãn protected

  • Từ khóa public được dùng để tạo các thành phần “protected – bảo mật” (Cho dữ liệu hoặc hàm) 
  • Các thành phần protected chỉ có thể truy cập trong class và các class kế thừa của nó.

Tổng quát

KiểuTrong chính classClass kế thừaBên ngoài
publicYesYesYes
privateYesNoNo
protectedYesYesNo
  1. Hàm khởi tạo và hàm hủy

Hàm khởi tạo là một hàm đặc biệt trong lớp. Hàm này được gọi tự động khi một đối tượng được tạo ra. Hàm khởi tạo sẽ khởi tạo giá trị cho các thuộc tính của đối tượng. Trong C++, một hàm khởi tạo có đặc điểm sau:

− Tên hàm khởi tạo trùng với tên của lớp.

− Hàm khởi tạo không có kiểu dữ liệu trả về (kể cả void).

− Hàm khởi tạo có thể là public, private hoặc protected. Hàm private có thể truy cập từ lớp friend, protected có thể gọi từ lớp kế thừa.

− Hàm khởi tạo có thể có đối số hoặc không có đối số.

− Trong một lớp có thể có nhiều hàm khởi tạo (cùng tên nhưng khác đối số).

XQUeJ5tuUCmdfPiZuaa7l4 kfr99 uKNPT fcYAS1yyZGs1gHLFohu7YaTZ22NRxhP 3HEHMdZ7yetmE 5LLmmjoAcKb aLhgyBZiijchDiwwwpzziaN fz8j RbMV2t 94 Jw32 52ouEgRmLYGQw - quochung.cyou PTIT

 Hàm khởi tạo mặc định (default constructor)

Hàm khởi tạo mà không có đối số nào thì được gọi là hàm khởi tạo mặc định. Hàm này thường dùng gán giá trị mặc định cho các thuộc tính trong lớp.

Trong ví dụ bên dưới, hàm Circle() là một hàm khởi tạo mặc định và tự đặt r = 1 nếu chưa cài r.

- quochung.cyou PTIT

Lưu ý: Nếu lớp không có hàm khởi tạo nào, trình biên dịch sẽ cung cấp một hàm khởi tạo mặc định không đối số và không code trong nó.

Nếu trong lớp đã có ít nhất một hàm khởi tạo thì hàm khởi tạo mặc định do trình biên dịch cung cấp sẽ không còn nữa. Khi đó, bạn phải sử dụng các hàm khởi tạo được định nghĩa trong lớp nếu không sẽ gây ra lỗi.

Vnaot vBBOcs CkvdX 6a17fiR4RmGEtkjP vqjE8Fzan7uMRcFliLBLZTgZhutiDq5VfvdLoNHP88 rLNpZVcoAaqCp XeDTyGozJle4RsNoQ6NWDIDAIitR44mnftAo1H8HCYqstLm2i TF54qIw - quochung.cyou PTIT

Hàm huỷ sẽ tự động được gọi trước khi giải phóng một đối tượng để giải phóng vùng nhớ trước khi đối tượng được hủy bỏ. Hàm hủy có các đặc điểm sau:

− Mỗi lớp chỉ có một hàm hủy.

− Hàm hủy không có kiểu, không có giá trị trả về và không có đối số.

− Tên hàm huỷ cùng tên với tên lớp và có một dấu ngã (~) ngay trước tên.

w29IEuvUbhgSWYiwv0XNRZsUs5pnhlO8U7a9Jm2SbNGotBSRFJxcd1Pc9FBdNfLLNsLUR3Enp6l1ZT4n1jO ho AnqGW5wklXX6SsGS6WfU6uZabfCYByMwO4dUffsvujTYosAV22R97ZuAV35y8ew - quochung.cyou PTIT
  1. Getter và SetterbZtWeYVc93RF9jxumWG2W UscRZzz x90pjaS88rewCNSpIz6Xh7JDliDnvisncvatxhKOzUEt5yGQ - quochung.cyou PTIT

Là các hàm dùng để set (đặt) hoặc get (lấy) dữ liệu

  1. Static

Static trong C++ là một toán tử có tác dụng chỉ định một biến hoặc hàm thành viên trong class tồn tại ở dạng tĩnh.

Dạng tĩnh ở đây có ý nghĩa, vùng bộ nhớ dùng để lưu trữ các dữ liệu này sẽ là bất biến, không thay đổi.

Bằng việc sử dụng static trong class C++, chúng ta sẽ có được biến static và hàm static, là các thành viên được lưu tại các vùng bộ nhớ bất biến. Vì ở dạng tĩnh nên chúng sẽ tồn tại duy nhất trong class. Chúng có thể sử dụng kể cả không có đối tượng trong class

O9FVSTRGZXdoSY11q IDpeTUYejM2BoQsIYHvQflsDxzyt0W8flmXIe7VzRm4OHcMGWrCA9kp4uN3p7PJ 1vGRDONJ068lqnrrALyw AeitPeMb0mXDKa q Y cXAFN6xE 6eCAQggCQ - quochung.cyou PTIT

6.1. Biến static

Để tạo biến static trong class C++, chúng ta thêm toán tử static vào đằng trước tên biến khi khai báo biến trong class như sau. Lưu ý là access modifier của biến static phải ở dạng public để cho phép truy cập nó từ ngoài phạm vi class.

Ưu điểm lớn nhất của biến static đó chính là chúng ta có thể sử dụng trực tiếp nó mà không cần phải tạo ra đối tượng (instance) từ class. Tuy nhiên do không tạo ra instance dẫn đến việc giá trị ban đầu của biến static cũng không được khởi tạo, nên khi dùng biến static mà không tạo ra đối tượng, chúng ta cần phải khởi tạo giá trị cho nó ở bên ngoài phạm vi class.

Ví dụ:

VjdwUs zBdsnMUzInd5E ohUzrsk5z3qzjrCxDuK3iw2rQHX 1llE1pjPiSvIr8BWe9O4gBlSIeu58kIvJdK9CXQRTDG yWlsQSm6W9J866Z 0ndY5chkjXRo7OeBpgcyEGQ CFHQJ13bbYsHwz0Q - quochung.cyou PTIT

Giống như ví dụ trên, do sNum là biến static nên chúng ta có thể trực tiếp sử dụng giá trị của nó mà không cần phải tạo ra đối tượng từ class. Tuy nhiên biến num thì chỉ là biến thành viên bình thường nên chúng ta không thể sử dụng trực tiếp nó vì lỗi sẽ xảy ra.

6.2. Hàm static

Để tạo hàm static trong class C++, chúng ta thêm toán tử static vào đằng trước tên hàm khi khai báo hàm trong class như sau. Lưu ý là access modifier của hàm static phải ở dạng public để cho phép truy cập nó từ ngoài phạm vi class.

Lưu ý: đối với các hàm static thì các biến sử dụng bên trong phải là biến static

Ví dụ:

9LO5wMGm97Qb291ve6J AvXkWn8VTs l yllM5W - quochung.cyou PTIT
  1. Kỹ thuật chia tách file trong C++

Headers file

Khi các chương trình phát triển ngày càng lớn (và sử dụng nhiều file hơn), Việc khai báo các hàm bạn muốn sử dụng được định nghĩa trong cùng một file sẽ trở nên ngày càng tẻ nhạt và làm cho file đó trở lên nhiều dòng code, khó kiểm soát. Sẽ tốt hơn nếu bạn có thể đặt tất cả các khai báo của mình ở một nơi và sau đó định nghĩa chúng khi bạn cần nó.

Viết một file header

Ví dụ chúng ta có hai tệp, add.cpp và main.cpp, trông giống như thế này:

LNlR7gRsreZomKD6JOtH8Unnc9isFedY8yTE0S3Bu6HwYVX6x7N2E r2uZ6e3FBIzDwctFkyk4VGkdEeFH1Nwd hGD7Jq7yvAF6tbrvNhAYX1 PP GOTc0sGhuiQllSrpL7CIb4W8tvwjvd4wb64yw - quochung.cyou PTIT

Trong ví dụ này, chúng ta đã sử dụng một khai báo để trình biên dịch sẽ biết định danh add là gì khi biên dịch main.cpp. Chúng ta có thể thấy việc thêm thủ công cho mọi hàm bạn muốn sử dụng trong một file khác khá nhiều và phức tạp.

Hãy viết một file header để giảm bớt gánh nặng này. Viết một file header rất dễ dàng, vì các file header chỉ bao gồm hai phần:

Các tiền chỉ thị trong file header.

Nội dung thực tế của file header, phải là khai báo cho tất cả các định danh mà chúng ta muốn các file khác có thể nhìn thấy.

Sử dụng hậu tố .h khi đặt tên file header

Các file header thường được ghép nối với các file code, với file header cung cấp các khai báo cho file code tương ứng. Vì file header của chúng ta sẽ chứa một khai báo cho các hàm được định nghĩa trong add.cpp, nên chúng ta sẽ gọi file header mới là add.h.

Nếu một file header được ghép nối với một file code (ví dụ: add.h với add.cpp), cả hai sẽ có cùng tên (add).

File add.h

doyig TXI0hIRsuVPmObj7bZanklmCVvX2JlvwD - quochung.cyou PTIT

Để sử dụng file header này trong main.cpp, chúng ta phải #include nó (sử dụng dấu ngoặc kép, không phải dấu ngoặc nhọn).

main.cpp

ArtV1BocMhzCaB KwzB2ZjkXZIcCRAWFwK9WMiHbJ3dLd CDJTnN5nXTlctRy3Ny8yyh3oNFcqVOlsx2F5cDQhnZnh64Cx 4NSHdjEFTzVLZEjmiITMWm4m8WA1hTbd2FffRTS1PsxSTxRlVu O5CQ - quochung.cyou PTIT

Quy tắc đặt tên biến trong OOP C++

Luôn sử dụng tiếng Anh để đặt tên hàm và biến.

Ví dụ:

/* Bad */

const hoTen = “Trạng Tí”

const banBe = [“Sửu Ẹo”, “Dần Béo”, “Cả Mẹo”]

/* Good */

const fullName = “Trạng Tí”

const friends = [“Sửu Ẹo”, “Dần Béo”, “Cả Mẹo”]

Quy ước đặt tên

Nếu team của bạn chọn quy ước đặt tên là camelCase, hãy sử dụng camelCase cho toàn bộ dự án, nếu bạn qua một team khác chuộng snake_case hơn, hãy tuân thủ nghiêm ngặt. Cho dù là quy ước nào thì điều quan trọng nhất chính là tính nhất quán.

/* Bad */

const page_count = 5

const isUser = true

/* Good */

const pageCount = 5

const isUser = true

Nguyên tắc S-I-D

Short (ngắn gọn): tên không được dài, không phải mất thời gian để gõ và nhớ.

Intuitive (tự nhiên): tên khi đọc lên phải cho cảm giác xuôi tai, gần gũi với văn nói.

Descriptive (súc tích): tên phải mô tả được ý nghĩa, tác dụng của nó, bằng cách hiệu quả nhất.

/* Bad */

const totalNumberOfPublishedArticles = 10 // tên quá dài

const a = 5 // “a” không mô tả được số 5 để làm gì

const isDisplayable = a > 5 // “isDisplayable” nghe không tự nhiên lắm

/* Good */

const totalArticles = 10

const postCount = 5

const shouldDisplay = postCount > 5

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply