Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 1 TÓM TẮT CHƢƠNG 3 : C++/CLI HƢỚNG ĐỐI TƢỢNG.
PHẦN A : GIỚI THIỆU TỔNG QUAN
1) Tổng quan về các phƣơng pháp lập trình :
a) Lập trình tuyến tính :
Đây là phương pháp lập trình ra đời đầu tiên. Đặc trưng cơ bản của lập trình tuyến tính là
tu duy theo lối tuần tự : chương trình được thực hiện từ đầu đến cuối, lệnh này kế tiếp lệnh kia cho
đến khi kết thúc chương trình.
Đặc trưng của lập trình tuyến tính :
Đơn giản : lập trình theo lối tuần tự, không phức tạp.
Đơn luồng : chỉ có một luông công việc được thực hiện tuần tự.
Nhược điểm :
Không thể thực hiện được các chương trình phức tạp.
Chương trình dài.
b) Lập trình cấu trúc :
Trong lập trình cấu trúc, chương trình chính được chia nhỏ thành các chương trình con,
mỗi chương trình con thực hiện một công việc xác định (chương trình con chính là các hàm).
Chương trình sẽ gọi đến chương trình con bằng một giải thuật hay một cú pháp nhất định trong
chương trình. Một chương trình con có thể được gọi nhiều lần trong chương trình chính.
Đặc trưng của lập trình cấu trúc
Chương trình bao gồm hai thành phần chính : cấu trúc dữ liệu và giải thuật. Cấu trúc
dữ liệu là cách thức tổ chức dữ liệu, cách mô tả bài toán dưới dạng ngôn ngữ lập
trình. Giải thuật là qui trình để thực hiện bài toán đó.
Giải thuật luôn luôn phụ thuộc vào cấu trúc dữ liệu.
Nhược điểm :
Không hỗ trợ việc sử dụng lại mã nguồn do giải thuật luôn phụ thuộc vào cấu trúc
dữ liệu. Khi thay đổi cấu trúc dữ liệu thì đồng thời phải thay đổi luôn cả giải thuật.
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.
VD : Trong bài toán quản lí Sinh viên ở trường Đại học thì mỗi Sinh viên có thể được xem
là một đối tượng. Các Sinh viên sẽ được phân biệt với nhau thông qua Họ tên. Mỗi Sinh viên lại
được mô tả bởi Ngày sinh, Nơi sinh, MSSV, Ngành học, Điểm số … ; đây chính là các thuộc tính
của đối tượng Sinh viên. Người quản lí muốn tác động đến thông tin của một Sinh viên nào đó thì
phải thông qua các phương thức của đối tượng Sinh viên như : Xem ngày sinh, Xem nơi sinh,
Nhập điểm số, Xem điểm số, Sửa điểm số …
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.
Tính đóng gói (Encapsulation) :
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 3
Các đối tượng có những thuộc tính tương tự nhau được gom thành một nhóm (lớp). Các
thuộc tính chung nhất của các đối tượng sẽ được giữ lại và các thuộc tính chung này sẽ trở thành
các thuộc tính của lớp.
VD : trong nhóm các đối tượng là phương tiện giao thông, nếu chúng ta nhóm các đối
tượng có chung thuộc tính là : 2 bánh, có động cơ … thì chúng ta sẽ có nhóm xe máy. Nếu chúng
ta nhóm các đối tượng có chung thuộc tính là : có 4 bánh, có động cơ … thì chúng ta sẽ có nhóm
xe ôtô.
Trong nhóm xe máy, có xe có gương chiếu hậu, có xe không có, như vậy gương chiếu hậu
không phải là thuộc tính chung và không được xem là thuộc tính của nhóm.
Việc truy xuất đến các dữ liệu được thực hiện thông qua các phương thức được trang bị
cho nhóm. Nếu người sử dụng muốn thay đổi các thay đổi trạng thái của đối tượng thì bắt buộc
phải thông qua các phương thức này. Việc cho phép môi trường bên ngoài tác động lên các dữ
thường dùng các biến để mô tả các thuộc tính và các hàm để mô tả các phương thức của đối
tượng. Khi đã định nghĩa được lớp, ta có thể tạo ra các đối tượng từ lớp này. Để việc sử dụng
được dễ dàng, thông qua hệ thống hàm tạo (constructor), người ta dùng lớp như một kiểu dữ liệu
để tạo ra các đối tượng. Nói tóm lại, lớp luôn luôn được đặc trưng bởi các thuộc tính và phương
thức.
Lớp con (subclass)
Lớp con là một lớp thông thường nhưng có thêm tính chất kế thừa một phần hay toàn bộ
các đặc tính của một lớp khác. Lớp mà có các tính chất được lớp con kế thừa gọi là Lớp cha
(parent class).
Lớp trừu tƣợng (abstract class)
Lớp trừu tượng là lớp mà ta không thể thực thể hóa thành đối tượng (tạo ra đối tượng).
Thuộc tính (attribute)
Thuộc tính của một lớp bao gồm các biến, các hằng, hay tham số nội tại của lớp đó. Ở đây,
vai trò quan trọng nhất của các thuộc tính là các biến vì chúng sẽ có thể bị thay đổi trong suốt quá
trình hoạt động của một đối tượng. Các thuộc tính có thể được xác định kiểu và kiểu của chúng có
thể là các kiểu dữ liệu cổ điển hay đó là một lớp đã định nghĩa từ trước.
Phƣơng thức (method)
Phương thức của một lớp thường được dùng để mô tả các hành vi của đối tượng (hoặc của
lớp). Mỗi phương thức thường được định nghĩa là một hàm, các thao tác để thực hiện hành vi đó
được viết tại nội dung của hàm.
Người ta còn định nghĩa thêm vài loại phương thức đặc biệt:
Hàm tạo (constructor) là hàm được dùng để tạo ra một đối tượng, cài đặt các giá trị ban đầu
cho các thuộc tính của đối tượng đó.
Hàm hủy (destructor) là hàm dùng vào việc làm sạch bộ nhớ đã dùng để lưu đối tượng và
hủy bỏ tên của một đối tượng sau khi đã dùng xong, trong đó có thể bao gồm cả việc xóa
các con trỏ nội tại và trả về các phần bộ nhớ mà đối tượng đã dùng.
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 5
return 2*(Math::PI)*R;
}
UInt16 Dien_tich()
{
return (Math::PI)*R*R;
}
};
Trong ví dụ trên, chúng ta đã tạo ra 1 Class có tên là Hinh_tron quản lí các đối tượng là các
hình tròn có bán kính khác nhau. Class có một thuộc tính là R (cho biết bán kính của đối tượng
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 6
hình tròn) và hai phương thức là Chu_vi() (tính chu vi của một đối tượng hình tròn) và
Dien_tich() (tính diện tích của đối tượng).
Thuộc tính của class : R. Biến có kiểu dữ liệu là UInt16.
Phương thức của class : Chu_vi(), Dien_tich(). Các hàm không tham số có trả về giá trị.
2) Sử dụng Class:
Trong chương trình chính (hàm main()), để tạo ra một đối tượng từ ref class đã khai báo, ta
có hai cách :
Cách 1 : Dùng Handle^ :
Cú pháp : Class_name^ name = gcnew Class_name(); // name là tên đối tượng.
VD : Hinh_tron^ A = gcnew Hinh_tron(); // Tạo đối tượng hình tròn A.
Để truy xuất đến các biến và phương thức của ref class, ta dùng toán tử “->”.
VD : A->R = 5; // Gán giá trị 5 cho thuộc tính R của đối tượng.
Int16 x = A->Chu_vi(); // x = 31 ( 2*3.14*5 = 31.4 )
Int16 y = A->Dien_tich(); // y = 78 ( 5*5*3.14 = 78.5)
Cách 2 : Dùng stack :
đó, bắt buộc phải thông qua đối tượng. Có nghĩa là ta phải tạo một đối tượng của class trước rồi
sau đó mới có thể truy xuất các biến thành viên thông qua đối tượng này. Việc truy xuất đến các
biến thành viên được thực hiện thông qua toán tử “->” đối với đối tượng kiểu handle hay toán tử
“.” đối với đối tượng kiểu stack.
VD :
ref class Sinh_vien
{
public:
String^ Ho_ten; // các biến thành viên.
UInt32 MSSV;
String^ Nganh_hoc;
};
void main(void)
{
Sinh_vien^ A; // Tạo đối tượng kiểu handle.
Sinh_vien B; // Tạo đối tượng kiểu stack.
A->Ho_ten = “Nguyen Van A”; // Truy xuất đến biến thành viên
B.Ho_ten = “Nguyen Van B”;
A->MSSV = 8111123;
B.MSSV = 8111124;
Console::WriteLine(“{0}/t : {1}”,A->Ho_ten, A->MSSV);
Console::WriteLine(“{0} /t: {1}”,B.Ho_ten, B.MSSV);
Console::ReadKey();
}
Kết quả in ra màn hình : Nguyen Van A : 8111123
Nguyen Van B : 8111124
Lưu ý : Nếu không gán giá trị cho các biến thành viên tương ứng với đối tượng thì các biến này sẽ
có giá trị mặc định là giá trị mặc định của kiểu dữ liệu.
Các biến tĩnh còn cho phép truy xuất trực tiếp mà không cần phải thông qua đối tượng.
Việc truy xuất đến biến tĩnh có thể thông qua tên class và toán tử “::”; giá trị của biến là giá trị
mặc định đã gán cho biến trong class.
VD:
void main(void)
{
String^ a = Sinh_vien::Nganh_hoc;
Console::WriteLine(“Nganh hoc : {0}”, a);
Console::ReadKey();
}
Kết quả in ra màn hình : Nganh hoc : Co dien tu
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 9
Các biến tĩnh hay biến thành viên đều có thể được gán giá trị khác thông qua đối tượng.
Trong trường hợp muốn khai báo một biến hằng số có giá trị cho trước và không cho phép thay
đổi giá trị này, ta có thể khai báo biến dưới dạng biến hằng số (thêm từ khóa const khi khai báo).
VD :
ref class Sinh_vien
{
public:
String^ Ho_ten; // các biến thành viên.
UInt32 MSSV;
const static String^ Nganh_hoc = “Co dien tu” ; // Biến hằng số.
};
phương thức thành viên (hai phương thức thành viên trong ví dụ trên có sử dụng biến thành viên
R).
Các phương thức thành viên chỉ có thể được truy xuất thông qua đối tượng bằng toán tử
“->”.
Lưu ý : Class cũng cho phép khai báo các phương thức quá tải (overload method) giống như việc
khai báo các hàm quá tải (overload function).
Phƣơng thức tĩnh (static method) :
Phương thức tĩnh cũng tương tự như biến tĩnh : khi khai báo phương thức tĩnh thì thêm từ
khóa static, phương thức tĩnh cũng có thể truy xuất trực tiếp qua tên class và toán tử “::” . Tất cả
các biến hay tham số sử dụng trong phương thức tĩnh bắt buộc phải là các biến tĩnh.
VD :
ref class Sinh_vien
{
public:
// các biến thành viên tĩnh.
static String^ Ho_ten = “Nguyen Van A”;
static UInt32 MSSV = 8111111;
static String^ Nganh_hoc = “Co dien tu” ;
// Phương thức tĩnh
static void Show(Sinh_vien^ A)
{
Console ::WriteLine(“Ho va ten : ”+A->Ho_ten);
Console ::WriteLine(“MSSV : ”+A->MSSV);
Console ::WriteLine(“Nganh hoc : ”+A->Nganh_hoc);
}
};
Hinh_tron (UInt16 r)
{
R = r; // truyền giá trị cho biến R của class.
}
// Variable :
UInt16 R;
…
};
Khi tạo đối tượng, ta có thể khởi tạo các thuộc tính ban đầu của đối tượng thông qua
constructor thay vì phải gán trực tiếp. Vì có 2 cách tạo đối tượng nên tương ứng cũng có hai cách
gọi constructor.
VD : tạo và khởi tạo giá trị cho đối tượng A.
Kiểu Handle : Hinh_tron^ A = gcnew Hinh_tron(5) ;
Kiểu Stack : Hinh_tron A (5);
Trong ví dụ trên, đối tượng A sau khi được tạo thì giá trị biến R của A được gán giá trị 5.
Lưu ý : Nếu trong class đã có khai báo constructor, khi tạo đối tượng ta phải theo đúng cấu trúc
của constructor.
VD : Nếu trong class Hinh_tron đã có khai báo constructor, dòng lệnh sau khi tạo đối tượng sẽ
báo lỗi :
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 12
Kiểu Handle : Hinh_tron^ A = gcnew Hinh_tron() ; // Error
Kiểu Stack : Hinh_tron A ; // Error
Lí do là ta chưa truyền giá trị cho tham số của constructor khi khai báo.
Kiểu Handle : Hinh_tron^ A = gcnew Hinh_tron(0) ; // OK
Kiểu Stack : Hinh_tron A (0); // OK
Copy constructor :
VD :
void main(void)
{
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 13
Hinh_tron A(10);
Hinh_tron B = A; // Gán giá trị cho đối tượng B
Console::WriteLine(“Chu vi hinh tron B = {0}”,B.Chu_vi());
Console::ReadKey();
}
Kết quả in ra màn hình : Chu vi hinh tron B = 62
Destructor :
Destructor là một phương thức đặc biệt của class cho phép chúng ta xóa các đối tượng hay
phương thức đã được tạo trước đó. Mục đích của destructor là giúp giải phóng bộ nhớ đã được cấp
phát khi khởi tạo đối tượng đồng thời giải phóng các tài nguyên hệ thống đã được cung cấp cho
đối tượng. Destructor được khai báo bên trong Class.
Cú pháp : ~Class_name ()
{
Statement;
}
Lưu ý, chỉ nên khai báo destructor khi trong class có các biến kiểu con trỏ (array, string).
Để giải phóng bộ nhớ, ta dùng lệnh delete với các biến này.
VD :
ref class Sinh_vien
{
public :
// Variable :
String^ Ho_ten;
String^ Que_quan;
|| ++ ,
VD : Đoạn mã sau sẽ xây dựng Class Complex quản lí các đối tượng là các số phức (có dạng a +
bj). Mỗi đối tượng được đặc trưng bởi 2 biến : Re (phần thực) và Im (phần ảo). Trong Class có
định nghĩa toán tử “-” một tham số trên số phức A (a + bj) có chức năng trả về số phức liên hợp
của A (a – bj).
ref class Complex
{
public :
// Variable :
float Re;
float Im;
// Constructor :
Complex (float a, float b)
{
Re = a;
Im = b;
}
//Method :
void Show()
{
Console::WriteLine(Re+ “ + ” + Im);
}
//Operator :
static Complex^ operator - (const Complex^ A)
Lập trình ứng dụng trong kỹ thuật Chương 3
| ~ ! = < > +=
*= /= %= ^= |= << >>
<<= >>= == != <= >= &&
|| ++ ,
VD : Đoạn mã sau sẽ định nghĩa toán tử “+” cho Class Complex có chức năng cộng hai số phức.
ref class Complex
{
public :
// Variable :
float Re;
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 16
float Im;
// Constructor :
Complex (float a, float b)
{
Re = a;
Im = b;
}
//Method :
void Show()
{
Console::WriteLine(Re+ “ + ” + Im);
}
Class thừa kế hay class con là class được khai báo bên trong một class khác. Class chứa
class con được gọi là class cơ sở hay class dẫn xuất. Cú pháp khai báo class con cũng tương tự
như class thông thường.
Cú pháp
ref class Class_name1 // Khai báo class dẫn xuất
{
public:
ref class Class_name2 // Khai báo class con.
{
Statement; // Đoạn mã của class con.
};
Statement; // Đoạn mã của class cha.
} ;
VD :
ref class Hinh_tron
{
public :
// Variable :
UInt16 R;
// Method :
UInt16 Chu_vi()
{
return 2*(Math::PI)*R;
}
UInt16 Dien_tich()
{
return (Math::PI)*R*R;
Lưu ý : Nếu trong class đã có khai báo constructor, khi tạo đối tượng ta phải theo đúng cấu trúc
của constructor.
VD : Hinh_tron::Hinh_vuong^ A = gcnew Hinh_tron::Hinh_vuong(10);
Để truy xuất đến các biến và phương thức của ref class, ta dùng toán tử “->”.
VD : A->a = 5; // Gán giá trị 5 cho thuộc tính a của đối tượng.
UInt16 x = A->Chu_vi(); // x = 20
UInt16 y = A->Dien_tich(); // y = 25
Cách 2 : Dùng stack :
Cú pháp : Class_name1::Class_name2 name ; // name là tên đối tượng.
VD : Hinh_tron::Hinh_vuong A(5) ; // Tạo đối tượng hình tròn A.
Để truy xuất đến các biến và phương thức của ref class, ta dùng toán tử “.”.
VD : A.R = 5; // Gán giá trị 5 cho thuộc tính R của đối tượng.
UInt16 x = A.Chu_vi(); // x = 20
Lập trình ứng dụng trong kỹ thuật Chương 3
Bộ môn Cơ điện tử Trang 19
UInt16 y = A.Dien_tich(); // y = 25
Quay trở lại ví dụ về class Hinh_vuong là class con của Class Hinh_tron đã khai báo, trong
hàm main()
VD :
void main()