7.2.1. Khỏi niệm Lập trỡnh hướng đối tượng
Lập trỡnh hướng đối tượng (gọi tắt là OOP, từ chữ object-oriented programming), hay cũn gọi là
lập trỡnh định hướng đối tượng, là kĩ thuật lập trỡnh hỗ trợ cụng nghệ đối tượng. OOP được xem là giỳp tăng năng suất, đơn giản húa độ phức tạp khi bảo trỡ cũng như mở rộng phần mềm bằng cỏch cho phộp lập trỡnh viờn tập trung vào cỏc đối tượng phần mềm ở bậc cao hơn. Ngoài ra, nhiều người cũn cho rằng OOP dễ tiếp thu hơn cho những người mới học về lập trỡnh hơn là cỏc phương phỏp trước đú.
Một cỏch giản lược, đõy là khỏi niệm và là một nỗ lực nhằm giảm nhẹ cỏc thao tỏc viết mó cho người lập trỡnh, cho phộp họ tạo ra cỏc ứng dụng mà cỏc yếu tố bờn ngoài cú thể tương tỏc với cỏc chương trỡnh đú giống như là tương tỏc với cỏc đối tượng vật lý.
Những đối tượng trong một ngụn ngữ OOP là cỏc kết hợp giữa mó và dữ liệu mà chỳng được nhỡn nhận như là một đơn vị duy nhất. Mỗi đối tượng cú một tờn riờng biệt và tất cả cỏc tham chiếu đến đối tượng đú được tiến hành qua tờn của nú. Như vậy, mỗi đối tượng cú khả năng nhận vào cỏc thụng bỏo, xử lý dữ liệu (bờn trong của nú), và gửi ra hay trả lời đến cỏc đối tượng khỏc hay đến mụi trường.
7.2.2. Cỏc tớnh chất cơ bản
Đối tượng (object): Cỏc dữ liệu và chỉ thị được kết hợp vào một đơn vị đầy đủ tạo nờn một đối tượng. Đơn vị này tương đương với một chương trỡnh con và vỡ thế cỏc đối tượng sẽ được chia thành hai bộ phận chớnh: phần cỏc phương thức (method) và phần cỏc thuộc tớnh (attribute). Trong thực tế, cỏc phương thức của đối tượng là cỏc hàm và cỏc thuộc tớnh của nú là cỏc biến, cỏc tham số hay hằng nội tại của một đối tượng (hay núi cỏch khỏc tập hợp cỏc dữ liệu nội tại tạo thành thuộc tớnh của đối tượng). Cỏc phương thức là phương tiện để sử dụng một đối tượng trong khi cỏc thuộc tớnh sẽ mụ tả đối tượng cú những tớnh chất gỡ.
Cỏc phương thức và cỏc thuộc tớnh thường gắn chặt với thực tế cỏc đặc tớnh và sử dụng của một đối tượng.
Trong thực tế, cỏc đối tượng thường được trừu tượng húa qua việc định nghĩa của cỏc lớp (class). Tập hợp cỏc giỏ trị hiện cú của cỏc thuộc tớnh tạo nờn trạng thỏi của một đối tượng. Mỗi phương thức hay mỗi dữ liệu nội tại cựng với cỏc tớnh chất được định nghĩa (bởi người lập trỡnh) được xem là một đặc tớnh riờng của đối tượng. Nếu khụng cú gỡ lầm lẫn thỡ tập hợp cỏc đặc tớnh này gọi chung là đặc tớnh của đối tượng.
Lập trỡnh hướng đối tượng là một phương phỏp lập trỡnh cú cỏc tớnh chất chớnh sau:
Tớnh trừu tượng (abstraction): Đõy là khả năng của chương trỡnh bỏ qua hay khụng chỳ ý đến một số khớa cạnh của thụng tin mà nú đang trực tiếp làm việc lờn, nghĩa là nú cú khả năng tập trung vào những cốt lừi cần thiết. Mỗi đối tượng phục vụ như là một "động tử" cú thể hoàn tất cỏc cụng việc một cỏch nội bộ, bỏo cỏo, thay đổi trạng thỏi của nú và liờn lạc với cỏc đối tượng khỏc mà khụng cần cho biết làm cỏch nào đối tượng tiến hành được cỏc thao tỏc. Tớnh chất này thường được gọi là sự trừu tượng của dữ liệu.
Tớnh trừu tượng cũn thể hiện qua việc một đối tượng ban đầu cú thể cú một số đặc điểm chung cho nhiều đối tượng khỏc như là sự mở rộng của nú nhưng bản thõn đối tượng ban đầu này cú thể khụng cú cỏc biện phỏp thi hành. Tớnh trừu tượng này thường được xỏc định trong khỏi niệm gọi là lớp trừu tượng hay lớp cơ sở trừu tượng.
Tớnh đúng gúi (encapsulation) và che giấu thụng tin (information hiding): Tớnh chất này khụng cho phộp người sử dụng cỏc đối tượng thay đổi trạng thỏi nội tại của một đối tượng. Chỉ cú cỏc phương thức nội tại của đối tượng cho phộp thay đổi trạng thỏi của nú. Việc cho phộp mụi trường bờn ngoài tỏc
động lờn cỏc dữ liệu nội tại của một đối tượng theo cỏch nào là hoàn toàn tựy thuộc vào người viết mó. Đõy là tớnh chất đảm bảo sự toàn vẹn của đối tượng.
Tớnh đa hỡnh (polymorphism): Thể hiện thụng qua việc gửi cỏc thụng điệp (message). Việc gửi cỏc thụng điệp này cú thể so sỏnh như việc gọi cỏc hàm bờn trong của một đối tượng. Cỏc phương thức dựng trả lời cho một thụng điệp sẽ tựy theo đối tượng mà thụng điệp đú được gửi tới sẽ cú phản ứng khỏc nhau. Người lập trỡnh cú thể định nghĩa một đặc tớnh (chẳng hạn thụng qua tờn của cỏc phương thức) cho một loạt cỏc đối tượng gần nhau nhưng khi thi hành thỡ dựng cựng một tờn gọi mà sự thi hành của mỗi đối tượng sẽ tự động xảy ra tương ứng theo đặc tớnh của từng đối tượng mà khụng bị nhầm lẫn.
Thớ dụ khi định nghĩa hai đối tượng "hinh_vuong" và "hinh_tron" thỡ cú một phương thức chung là "chu_vi". Khi gọi phương thức này thỡ nếu đối tượng là "hinh_vuong" nú sẽ tớnh theo cụng thức khỏc với khi đối tượng là "hinh_tron".
Tớnh kế thừa (inheritance): Đặc tớnh này cho phộp một đối tượng cú thể cú sẵn cỏc đặc tớnh mà đối tượng khỏc đó cú thụng qua kế thừa. Điều này cho phộp cỏc đối tượng chia sẻ hay mở rộng cỏc đặc tớnh sẵn cú mà khụng phải tiến hành định nghĩa lại. Tuy nhiờn, khụng phải ngụn ngữ định hướng đối tượng nào cũng cú tớnh chất này.
7.2.3. Chức năng Hướng đối tượng 1) Lớp
Định nghĩa lớp cơ bản
Việc sử dụng lớp trong một chương trỡnh C++ cú hai phần chớnh là phần định nghĩa lớp và phần khai bỏo và truy cập cỏc thành viờn của một đối tượng cú kiểu là một lớp cho trước.
Định nghĩa thụng thường của một lớp cơ bản khụng kế thừa từ bất kỡ lớp nào khỏc: class myClass // tờn lớp
{
public:
(danh sỏch cỏc thành viờn cú đặc tớnh cụng cộng) private:
(danh sỏch cỏc thành viờn cú đặc tớnh riờng tư) protected:
(danh sỏch cỏc thành viờn cú đặc tớnh bảo tồn) }; // dấu chấm phẩy chấm dứt cõu lệnh
Lưu ý: khi cỏc từ khoỏ đặc tớnh public:, private: và protected: khụng cú mặt thỡ toàn bộ cỏc thành viờn của lớp sẽ được hiểu mặc định là cú đặc tớnh riờng tư (private).
Dựng khai bỏo biến myVar làm một thực thể (instance) của lớp myClass:
Định nghĩa thụng thường của một lớp con kế thừa từ lớp myClass. Trong thớ dụ dưới đõy thỡ [đặc_tớnh] cú thể thay bằng một trong ba từ khoỏ đặc tớnh public:, private: và protected: hoặc nếu bỏ qua khụng viết ra thỡ đặc tớnh kế thừa mặc định của lớp con sẽ là "riờng tư".
class mySubClass : [đặc_tớnh] myClass {
public:
(danh sỏch cỏc thành viờn cú đặc tớnh cụng cộng) private:
(danh sỏch cỏc thành viờn cú đặc tớnh riờng tư) protected:
(danh sỏch cỏc thành viờn cú đặc tớnh bảo tồn)
}; // dấu chấm phẩy chấm dứt cõu lệnh
Định nghĩa thụng thường của một lớp con kế thừa từ hai lớp myClass1 và myClass2. Tương tự trờn, [đặc_tớnh] cú thể thay bằng một trong ba từ khoỏ đặc tớnh public:, private: và protected: hoặc nếu bỏ qua khụng viết ra thỡ đặc tớnh kế thưà mặc định của lớp con sẽ là "riờng tư".
class mySubClass : [đăc_tớnh] myClass1, [đăc_tớnh] myClass2 {
public:
(danh sỏch cỏc thành viờn cú đặc tớnh cụng cộng) private:
(danh sỏch cỏc thành viờn cú đặc tớnh riờng tư) protected:
(danh sỏch cỏc thành viờn cú đặc tớnh bảo tồn)
}; // dấu chấm phẩy chấm dứt cõu lệnh
Khai bỏo một biến đối tượng
Biến đối tượng thụng thường
Biến đối tượng cú thể khai bỏo hay đụi khi cũn gọi là thực thể hoỏ tựy theo cỏch xõy dựng lớp của người lập trỡnh. Thường quỏ trỡnh xỏc lập này được tiến hành thụng qua cỏc hàm dựng. Dĩ nhiờn, người ta cú thể dựng ngay cả cỏc phương thức thường dựng như là dựng tham chiếu (tức là dựng định nghĩa con trỏ), dựng mảng, dựng cấu trỳc, hay phức tạp hơn (mảng tham chiếu chẳng hạn) để khai bỏo một biến đối tượng. (Xem thờm Cỳ phỏp ngụn ngữ C.) Trong mọi trường hợp này thỡ kiểu của biến đối tượng được xem là lớp mà nú khai bỏo. Thớ dụ:
myClass A10; //biến thụng thường myClass *A10ptr = new myClasss; //biến con trỏ
&myClassRef = A10; //biến kiểu tham chiếu (ngược)
Lưu ý: người lập trỡnh hoàn toàn cú thể thực thể hoỏ một biến đối tượng mà khụng cần phải xõy dựng một hàm dựng, trỡnh dịch sẽ tự tạo ra một "hàm dựng mặc định". Tuy nhiờn, một khi đó xõy dựng bất kỡ một hàm dựng nào thỡ cỏch khai bỏo mặc định này sẽ khụng cũn được trỡnh dịch chấp thuận và sẽ bỏo lỗi. Thớ dụ sau đõy thể hiện cỏch tạo một lớp mà khụng cần hàm dựng:
#include <iostream> using namespace str; class number { private: int x; public:
void setValue (int y) { x= y;}
void getValue () {cout << x << endl;} }; main () { number myNumber; myNumber.setValue(4); myNumber.getValue(); }
Biến đối tượng là một hằng
Trường hợp khi thành lập một đối tượng hằng thỡ việc điều chỉnh trạng thỏi nội tại của nú là khụng hợp lệ do đú, chỉ cú một cỏch duy nhất là gỏn cho nú một bộ giỏ trị (hay một trạng thỏi) ban đầu. Trong trường hợp này thỡ sau khi đó thực thể húa, biến đối tượng chỉ cú thể cho phộp đọc cỏc giỏ trị nào mà lớp tạo ra nú cho phộp. (xem thớ dụ)
Cỏc thành viờn của lớp
Thành viờn dữ liệu
Ngoài cỏc khai cỏo thành viờn cú kiểu dữ liệu như thụng thường trong C, thỡ người lập trỡnh cũn cú thể khai bỏo nú như một hằng, hay như một biến tĩnh, hay cú cả hai đặc tớnh:
Thành viờn dữ liệu là một hằng: Trương tự như trong C, một thành viờn là dữ liệu cú thể được khai bỏo như là một hằng bởi từ khúa const đứng trước tờn kiểu dữ liệu. Một khi đó khai bỏo là hằng thỡ khụng thể gỏn giỏ trị mới hay thay đổi nội dung của kiểu dữ liệu đú nữa (Lưu ý: trong C++ thỡ kiểu dữ liệu cú thể là một lớp đó được định nghió). Do đú, dữ liệu là hằng sẽ được gỏn giỏ trị ban đầu ngay trong dũng lệnh khai bỏo tờn của nú:
Thành viờn dữ liệu cú kiểu static: Một khi thành viờn của một lớp cú kiểu là static thỡ nú sẽ cú giỏ trị tĩnh cho mọi thực thể của cựng một lớp. Nghĩa là sự thay đổi giỏ trị của thành viờn tĩnh này trong một thực thể bất kỡ sẽ cú hiệu quả thay đổi của cựng thành viờn đú trong cỏc thực thể khỏc của cựng một một lớp. Thực tế, khi một thành viờn của một lớp được khai bỏo tĩnh thỡ phần bộ nhớ chứa giỏ trị của thành viờn này sẽ được chia sẽ cho mọi thực thể về sau. Núi cỏch khỏc, ứng với mỗi thành viờn tĩnh, chỉ cú duy nhất một giỏ trị chia sẽ chung cho cả lớp.
Thành viờn dữ liệu cú thể cú cả hai đặc tớnh trờn tức là vừa cú kiểu tĩnh vừa là hằng số. Thường từ khúa static được viết trước sau đú là từ khúa const. Thớ dụ dưới đõy minh họa cỏc cỳ phỏp khai bỏo. việc sử dụng một biến hằng cú kiểu tĩnh rất tiện lợi cho nhiều đối tượng thực thể húa cú cựng một lớp chia sẽ chung một hằng số (thớ dụ: hằng số Pi dựng chung cho cỏc đối tượng cung trũn, đường trũn, và elipse). Ngược lại, khi cú cỏc hằng số đặc thự cho từng thực thể của một lớp thỡ một cỏch là dựng hằng số thụng thường (chẳng hạn như cựng một lớp "chiết tớnh tiền lời cho vay" nhưng thực thể ngắn hạn cú "hằng số lói kộp" cao hơn nhiều so với hằng số lói kộp dài hạn). Thớ dụ dưới đõy minh họa cỳ phỏp khai bỏo #include <iostream> #include <string> using namespace std; class A { public:
A(int x, int y);
void setStatic (int x) { value= x; } //hàm thành viờn xỏc lập trực tiếp trong dũng lệnh khai bỏo
void setNormal (int x) { normal=x; }
void getValue() const { cout<< "value "<< value << endl;}
void getShareConst() const {cout << "shareconst :" << shareconst << endl;} void getPrivate() const;
void getNormal() const {cout << "normal variable :" << normal << endl;} private:
static int value;
static const int shareconst; const int privateconst; int normal;
};
int A::value=3; //gỏn giỏ trị cho biến tĩnh ở đõy dựng chung cho mọi biến của lớp A (=3)
A::A(int x, int y):privateconst(y) //Hàm dựng: cỏch gỏn giỏ trị ban đầu cho một hằng thụng thường
{
normal=x; //gỏn giỏ trị ban đầu cho biến thụng thường }
void A::getPrivate() const //cỏch để xỏc lập mó cho hàm thành viờn bờn ngoài dũng lệnh khai bỏo của lớp
{
cout <<"privateconst :" << privateconst << endl; }
int main () {
A A1(3,1); // giỏ trị hằng privateconst của A1 được gỏn ở đõy (=1) A A2(5,2); // giỏ trị hằng privateconst của A2 được gỏn ở đõy (=2)
A1.getPrivate(); A2.getPrivate();
A1.getShareConst(); //đọc giỏ trị hằng của biến tĩnh trong A1
A2.getShareConst(); //biến tĩnh trong A2 cú cựng giỏ trị với biến tĩnh của A1 A1.setValue(4); //cài đặt cho biến tĩnh value cho đối tượng A1
A2.getValue(); //Cài dặt từ A1 nhưng lại cú giỏ trị luụn cho đối tượng A2 return 0;
}
Kết quả sau khi dịch và chạy chương trỡnh trờn là: 1
2 3 3 4
Lưu ý: bạn sẽ khụng thể gỏn giỏ trị nào khỏc ngoài cỏc giỏ trị ban đầu khi khai bỏo cho cỏc hằng. Trong thớ dụ trờn hàm setValue sẽ cho phộp bạn gỏn lại giỏ trị tĩnh value của lớp A và nú ảnh hưởng đến mọi thực thể cựng lớp A. Trong khi hàm setNormal cho phộp gỏn lại giỏ trị cho biến normal thụng thường trong một thực thể của lớp A sẽ chỉ hiệu lực cho riờng thực thể đú mà thụi.