Giáo trình Lập trình hướng đối tượng C++ (Phần 1)
CodeBlocks
Trước tiên, chúng ta sẽ tìm hiểu cách tạo dự án, biên dịch một tập tin C++
trên CodeBlocks. Độc giả cũng cần lưu ý rằng, CodeBlocks tổ chức công việc
theo các dự án. Chúng ta có thể biên dịch từng tập tin cpp một c|ch đơn lẻ.
Tuy nhiên, làm việc theo dự án sẽ giúp ích cho chúng ta rất nhiều khi làm
việc với những tác vụ lớn.
Đầu tiên chúng ta khởi động codeblocks, sau đó v{o File > New > Project.
Trong hộp thoại hiện ra, chúng ta chọn console application (Hình 1).
Và nhấp Go, sau đó nhấp Next. Trong hộp thoại tiếp theo, ta chọn C++ và
nhấp Next
CodeBlocks
Trước tiên, chúng ta sẽ tìm hiểu cách tạo dự án, biên dịch một tập tin C++
trên CodeBlocks. Độc giả cũng cần lưu ý rằng, CodeBlocks tổ chức công việc
theo các dự án. Chúng ta có thể biên dịch từng tập tin cpp một c|ch đơn lẻ.
Tuy nhiên, làm việc theo dự án sẽ giúp ích cho chúng ta rất nhiều khi làm
việc với những tác vụ lớn.
Đầu tiên chúng ta khởi động codeblocks, sau đó v{o File > New > Project.
Trong hộp thoại hiện ra, chúng ta chọn console application (Hình 1).
Và nhấp Go, sau đó nhấp Next. Trong hộp thoại tiếp theo, ta chọn C++ và
nhấp Next
iên dịch chương trình:
+ Nhấp vào Build > Build and Run.
+ Hoặc nhấp phím F9.
Tự động định dạng mã. Khi viết một chương trình C++ hay bất kì một
chương trình trên một ngôn ngữ lập trình nào
khác, ta cần tuân thủ quy phạm định dạng mã
nguồn. Có nhiều chuẩn mực cho c|c định dạng
mã nguồn: chuẩn Hungary, chuẩn lạc đ{. Dù
rằng, chúng không ảnh hưởng đến việc biên dịch
chương trình, nhưng chúng giúp người đọc có
thể dễ hiểu chương trình của chúng ta hơn. Nếu
ta không nắm vững các quy phạm này thì có thể
sử dụng chức năng định dạng mã nguồn tự động
của CodeBlocks. Hãy kích chuột phải vào vùng soạn thảo, sau đó chọn
Format this file (Astyle).
Tự động khởi tạo phần thân các phương thức của lớp. Để hỗ trợ cho
việc soạn thảo, CodeBlocks cũng hỗ trợ chức năng khởi tạo nhanh mã
nguồn. Để khởi tạo nhanh phần khai b|o th}n phương thức của lớp từ khai
báo prototype của nó, chúng ta đặt trỏ chuột vào sau khai báo lớp (tức vị trí
sẽ chèn khai b|o th}n phương thức), sau đó, kích chuột phải, chọn Insert >
All class methods without implementation.

Trang 1

Trang 2

Trang 3

Trang 4

Trang 5

Trang 6

Trang 7

Trang 8

Trang 9

Trang 10
Tải về để xem bản đầy đủ
Tóm tắt nội dung tài liệu: Giáo trình Lập trình hướng đối tượng C++ (Phần 1)
thất bại v{ ngược lại thì thành công. Đ}y l{ c|ch
làm thủ công, chúng ta có thể sử dụng cấu trúc try catch để xử lý tình
Chương 10. Bộ nhớ động
T r a n g | 109
C
+
+
huống này. Chi tiết, chúng ta sẽ thảo luận kĩ hơn trong phần sau. Lưu ý rằng,
hai ngoại lệ này nằm trong thư viện .
Toán tử delete và delete[]
Nếu khi biến trỏ không cần dùng đến nữa, chúng ta có thể xóa bỏ các
ô nhớ của nó để giải phóng bộ nhớ động. Qu| trình n{y được thực thi bởi
toán tử delete.
delete num;
delete[] nums;
Cách viết thứ nhất dùng để giải phóng con trỏ đơn tầng. Cách thứ hai
dùng cho con trỏ đa tầng (hai tầng trở lên).
Toán tử delete chỉ có tác dụng với con trỏ được khởi tạo bởi toán tử
new hoặc con trỏ null.
Chương trình Kết quả
#include
#include
using namespace std;
int main()
{
double *ptr[ 5];
for ( int i = 0; i < 5; i++ )
{
ptr[ i ] = new (nothrow) double[ 50000000 ];
if (ptr[i]!=0)
cout << "Allocation is ok";
else
cout<<”Allocation fail”;
}
delete[] ptr;
return 0;
}
Allocation is ok
Allocation is ok
Allocation is ok
Allocation is ok
Allocation fail
Trong ANSI-C, hàm malloc, calloc, realloc v{ free được dùng thay cho
new và delete và hiển nhiên chúng cũng hoạt động trên C++. Chúng ta
không thảo luận chi tiết về h{m n{y, vì theo xu hướng của lập trình C++
hiện đại, người ta sử dụng hai toán tử new và delete mà ta thảo luận ở trên.
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
Trang | 110
CHƯƠNG 11. KIỂU DỮ LIỆU STRUCT VÀ CON
TRỎ STRUCT
Kiểu dữ liệu mảng m{ chúng ta đ~ thảo luận ở trên chỉ giúp chúng ta
lưu một tập dữ liệu cùng loại. Nếu chúng ta không đơn thuần lưu trữ cùng
loại dữ liệu, mà có thể là nhiều kiểu dữ liệu khác nhau, thì mảng không thể
giải quyết được vấn đề. Trong C++ (và cả C) cung cấp cho chúng ta một kiểu
dữ liệu giúp ta giải quyết vấn đề n{y, đó l{ struct.
Struct
Một dữ liệu struct là một nhóm các phần tử có thể có kiểu dữ liệu
kh|c nhau được đặt cùng một tên. Các phần tử dữ liệu n{y được gọi là các
thành viên của struct. Cấu trúc khai b|o struct trong C++ như sau
struct tên_struct{
type thành_viên_1;
type thành_viên_2;
} [tên_đối_tượng_struct];
Trong đó:
struct là một từ khóa.
tên_struct là tên kiểu dữ liệu struct m{ ta định nghĩa.
thành_viên_1, l{ c|c phần tử thành viên của struct.
tên_đối_tượng_struct: là tên biến thuộc kiểu tên_struct.
Hai c|ch khai b|o sau đ}y l{ tương đương.
Ví dụ 1 Ví dụ 2
struct product{
int weight;
float price;
}
product apple;
product banana, melon;
struct product{
int weight;
float price;
}apple, banana, melon;
Giải thích: trong hai ví dụ trên product là kiểu dữ liệu struct mà ta tạo ra.
Nó gồm có hai th{nh viên l{ weight v{ price. Tương ứng với kiểu dữ liệu
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
T r a n g | 111
C
+
+
này, ta có các biến apple, banana, melon. Để khai báo nó, ta có thể sử dụng
một trong hai c|ch theo như hai ví dụ này. Cần lưu ý rằng, các biến apple,
banana, melon là các biến thuộc kiểu dữ liệu product.
Để truy cập đến các thành viên của biến struct, ta sử dụng toán tử chấm (.).
apple.weight = 200;
apple.price = 2;
banana.weight = 150;
banana.price = 1;
Chúng ta có thể hiểu apple.weight là khối lượng của táo, apple.price là
giá tiền của táo... Có thể xem mỗi thành viên của một biến struct như là một
biến độc lập mà ta có thể truy cập bằng cách
tên_biến.phần_tử_thành_viên. Ta hoàn toàn có thể thực hiện các phép
to|n tương ứng với mỗi dữ liệu th{nh viên n{y (nghĩa l{ c|c phép to|n đó
tương ứng với các phép toán trên kiểu dữ liệu của các phần tử thành viên
đó: nếu phần tử thành viên là kiểu nguyên thì ta có thể thực hiện các phép
toán số nguyên với thành viên này, nếu phần tử thành viên là kiểu xâu thì
có thể thực thi các phép toán với xâu cho biến thành viên này,).
Ví dụ, tôi mua 400gam táo, và 300g chuối. Giá của mỗi 100g táo là 1$, và
100g chuối là 0.7$. Cần tính toán số tiền mà tôi cần trả.
Ví dụ
apple.weight = 400;
apple.price = (float)apple.weight*1/100;
banana.weight = 300;
banana.price = banana.weight*0.7/100;
float money = apple.price+banana.price;
Như trong ví dụ trên, tôi có thể thực hiện các phép toán số học với các phần
tử thành viên là kiểu số như c|c biến số bình thường.
Struct là một kiểu dữ liệu do người dùng định nghĩa (nhờ vào từ khóa
struct – từ khóa struct viết thường). Ta cũng có thể khai báo một mảng các
phần tử thuộc kiểu struct. Ví dụ sau đ}y minh họa cho việc mua bán khi đi
siêu thị.
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
T r a n g | 112
C
+
+
Bài toán: Trong siêu thị, giá táo và chuối được ấn định trên từng sản phẩm
tùy thuộc chất lượng của sản phẩm, không phụ thuộc vào khối lượng của nó.
a. Tính khối lượng hàng hóa (kg) mà người tiêu dùng mua.
b. Nếu khách hàng mua hàng trị giá trên 10$, thì người tiêu dùng sẽ được
khuyến mãi. Hãy kiểm tra xem người tiêu dùng có được khuyến mãi
hay không.
Biết rằng số lượng táo và chuối do người tiêu dùng lựa chọn.
Chương trình Kết quả
#include
using namespace std;
#define MAX 10
struct product{
int weight;
float price;
}apples[MAX], bananas[MAX];
/*
Khai báo hàm
*/
void buyProducts(product pd, string
name, int &weight, float &price)
{
int i = 0;
cout<<”Buy “<<name<<endl;
while (true){
cout<<”weight and price: <<endl;
cin>>pd[i].weight;
cin>>pd[i].price;
weight += pd[i].weight;
price += pd[i].price;
cout<<”Continue to buy “<<name<<”
(y/n) ?”;
char yn;
cin>>yn;
if((yn==’n’)||(yn==’N’)) break;
else i++;
}
}
int main()
{
Buy apples
weight and price
100
2
Continue to buy apples (y/n) ?y
weight and price
200
3
Continue to buy apples (y/n) ?n
Buy bananas
weight and price
150
1
Continue to buy bananas (y/n)
?y
weight and price
250
3
Continue to buy bananas (y/n)
?n
Total weight: 0.7
No Promotion
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
T r a n g | 113
C
+
+
int weight = 0;
float price = 0;
buyProducts(apples, “apples”, weight,
price);
buyProducts(bananas, “bananas”,
weight, price);
cout<<”Total weight:
“<<(float)weight/1000<<endl;
if(price>10)
cout<<”Promotion”;
else
cout<<”No Promotion”;
return 0;
}
Giải thích:
Mảng apples và bananas thuộc kiểu dữ liệu product. Hàm
buyProducts dùng để tính toán khối lượng và tổng giá hàng hóa mỗi loại
mua được. Nếu tham số products trong hàm là apples, thì nó sẽ tính tương
ứng với khối lượng tổng cộng và tổng đơn giá của apples. Tương tự cho
bananas. Ta sử dụng vòng lặp while vì ta không biết chính xác số lượng
h{ng hóa m{ người dùng lựa chọn. Tuy nhiên, con số tổng không thể vượt
hằng số MAX m{ ta đ~ định nghĩa. Biến weight v{ price được truyền theo
tham biến, do đó, trước phép cộng dồn (toán tử cộng đồng nhất +=), ta
không cần khởi tạo giá trị 0 cho chúng, ta có thể khởi tạo cho chúng ngay
đầu hàm main. Nếu khởi tạo đầu hàm buyProducts, thì ta chỉ có thể tính
được khối lượng và giá của từng loại một mà thôi (khi đó, nếu muốn tính
toán cho cả hai sản phẩm, ta bổ sung thêm biến để lưu lại các giá trị này).
Sau khi gọi hàm này hai lần, tương ứng với apples và bananas, thì biến
weight lưu lại tổng khối lượng của cả hai sản phẩm, biến price lưu lại giá
của cả hai sản phẩm. Khối lượng được quy đổi sang kg, nên ta sẽ chia cho
1000. Nếu quy định đơn vị là kg, thì điều này là không cần thiết.
Trong phần thực thi chương trình, người tiêu dùng đ~ mua hai quả
táo và hai quả chuối. Quả táo thứ nhất có khối lượng 100g và giá 2$, quả táo
thứ hai – 200g và 3$. Quả chuối thứ nhất có khối lượng 150g và giá 1$, quả
chuối thứ hai – 250g và 3$.
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
T r a n g | 114
C
+
+
Con trỏ struct
Tương ứng với mảng struct, ta cũng có con trỏ trỏ vào struct. Với con
trỏ trỏ vào struct, ta có thể tạo ra một mảng struct động.
Khai báo con trỏ struct: có hai cách khai báo
struct product{
int weight;
float price;
}*apples;
struct product{
int weight;
float price;
};
product* apples;
Tham chiếu: ho{n to{n tương tự như con trỏ trỏ vào kiểu dữ liệu nguyên
thủy.
struct product{
int weight;
float price;
}apples1;
products* apples2;
apples2 = &apples1;
Truy cập giá trị của phần tử thành viên: có hai cách truy cập
apples2->weight
apples2->price
*(apples2.weight)
*(apples2.price)
Ta cần lưu ý sự khác nhau giữa apples2->weight và *apples2.weight.
Trường hợp đầu nó sẽ tương đương với *(apples2.weight) v{ theo độ ưu
tiên của toán tử, dấu () sẽ thực hiện trước tiên, nghĩa l{ th{nh viên weight
của apples2. Tiếp đó l{ phép to|n *. Điều này có thể hiểu là con trỏ apples2
trỏ v{o địa chỉ của biến thành viên weight của apples 2. Trường hợp thứ
hai, là giá trị trỏ bởi biến thành viên weight của apples2 (toán tử . có độ ưu
tiên cao hơn to|n tử *).
struct product{
int weight;
float price;
}*apples2;
.
apples2->weight
struct product{
int *weight;
float price;
}apples2;
*apples2.weight
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
T r a n g | 115
C
+
+
Struct lồng nhau
Struct có thể được khai báo lồng nhau. Chúng ta có thể khai báo lồng bên
trong, hoặc khai báo tuần tự
Khai báo lồng nhau Khai báo tuần tự
struct family{
string father;
string mother;
struct children{
string son;
string daughter;
}first, second;
}myfamily;
struct children{
string son;
string daughter;
};
struct family{
string father;
string mother;
children first, second;
}myfamily;
Khi đó, việc truy cập cũng tương tự như trên
myfamily.first.son
.
Nếu là con trỏ, ta cũng có c|ch truy cập tương tự.
struct family{
string father;
string mother;
struct children{
string son;
string daughter;
}*first, second;
}*myfamily;
myfamily->first->son
myfamily->second.son
Kích thước bộ nhớ của struct
Kích thước của struct theo lý thuyết nó sẽ l{ kích thước tổng cộng của
các dữ liệu thành viên. Tuy nhiên, theo cách thức tổ chức bộ nhớ, các dữ
liệu thành viên của một struct sẽ được sắp xếp liền kề nhau. Việc tổ chức bộ
nhớ của hệ thống máy tính 32bit sẽ theo xu hướng là nhóm 4 bytes. Điều
n{y có nghĩa l{, nếu dữ liệu thành viên thứ nhất đ~ lấp vào một số byte bộ
nhớ, và nếu còn thừa, thì hệ điều hành sẽ xem xét để đưa dữ liệu thành viên
tiếp theo vào. Nếu dữ liệu thành viên tiếp theo chiếm một số lượng các byte
bộ nhớ còn thừa, thì nó sẽ được lấp vào phần bộ nhớ còn thừa đó. Nhưng
nếu vượt quá, thì hệ thống sẽ được định hướng bổ sung thêm một nhóm 4
byte bộ nhớ mới để chứa dữ liệu thành viên tiếp theo (nếu cần nhiều hơn
Chương 11. Kiểu dữ liệu struct và Con trỏ struct
T r a n g | 116
C
+
+
thì cung cấp tiếp nhóm 4 byte nữa). Còn đối với số byte còn thừa, nó vẫn
được để trống.
Ví dụ 1 Ví dụ 2
struct number{
char a;
int b;
char c;
}mynum;
cout<<sizeof(mynum);
//12
struct number{
char a;
char c;
int b;
}mynum;
cout<<sizeof(mynum);
//8
Giải thích:
Trong ví dụ 1:
char – 1byte
int – 4byte
Đầu tiên, dữ liệu thành viên char sẽ
lấp đầy nhóm 4byte, char chiếm
1byte nên còn thừa 3 byte. Dữ liệu
thành viên tiếp theo là int. Vì int
chiếm 4byte, nhưng chỉ thừa có 3
byte, nó không đủ chỗ cho int. Do đó,
hệ thống sẽ tự động cung cấp thêm 3
byte để lấp đầy phần còn thừa. Tiếp
theo, sẽ cung cấp nhóm 4 byte cho
int. Không có byte thừa trong trường
hợp này. Kiểu dữ liệu thành viên
char còn lại chiếm 1byte, nhưng hệ
thống cung cấp cho nó 4 byte, còn
thừa 3 byte. Số byte thừa này sẽ
được lấp đầy. Như vậy, số byte trong
trường hợp này là
(1+3)+4+(1+3)=12 byte.
Trong ví dụ 2:
Cũng tương tự ví dụ 1. Dữ liệu thành
viên char thứ nhất chiếm 1 byte, hệ
thống cung cấp 4 byte, như vậy thừa
3 byte. Kiểu dữ liệu thành viên tiếp
theo cũng kiểu char, chiếm 1byte, nó
có thể lấp vào số byte còn thừa. Tại
thời điểm này, còn thừa 2 byte. Tiếp
theo, ta xét đến dữ liệu thành viên
int. Dữ liệu này chiếm 4 byte, nhưng
chỉ còn thừa 2 byte, do đó hệ thống
sẽ lấp đầy 2 byte này và cung cấp
thêm 4 byte mới cho int. Như vậy, số
byte trong trường hợp này là
(1+1+2)+4=8 byte.
Như vậy, tùy vào kiểu dữ liệu thành viên, ta cần chọn một cách sắp xếp hợp
lý để có một kết quả tối ưu về bộ nhớ. Hãy quan sát lược đồ sắp xếp bộ nhớ
hướng tối ưu như bên dưới (trường hợp 2).
char char int
Chương 12. C|c kiểu dữ liệu khác
Trang | 117
CHƯƠNG 12. CÁC KIỂU DỮ LIỆU KHÁC
Kiểu dữ liệu tự định nghĩa
Ta có thể định nghĩa một kiểu dữ liệu mới thông qua một kiểu dữ liệu
đ~ tồn tại
typedef kiểu_dữ_liệu_tồn_tại tên_kiểu_dữ_liệu_mới;
Sau khi khai báo kiểu dữ liệu mới, ta có thể sử dụng nó như kiểu dữ liệu
thông thường
typedef char C;
typedef char* pchar;
typedef char string50[50];
C mychar;
pchar p;
string50 str;
Kiểu dữ liệu union thường
Với từ khóa union, ta có thể khai báo một kiểu dữ liệu mới từ các kiểu
dữ liệu đ~ tồn tại.
union Tên_kiểu_union{
kiểu_dữ_liệu_thành_viên_1 tên_thành_viên_1;
kiểu_dữ_liệu_thành_viên_2 tên_thành_viên_2;
}biến_kiểu_dữ_liệu_union;
Khi khái báo kiểu union, các dữ liệu thành viên sẽ được khai báo trên cùng
một không gian bộ nhớ vật lý. Kích thước của nó l{ kích thước của kiểu dữ
liệu thành viên lớn nhất.
Ví dụ
union myType{
char C;
double Db;
} newType;
//8 byte, vì double = 8byte, char = 1byte.
Chương 12. C|c kiểu dữ liệu khác
T r a n g | 118
C
+
+
//Sử dụng
biến_kiểu_dữ_liệu_union.tên_thành_viên
Kiểu dữ liệu union ẩn danh
Ho{n to{n tương tự với kiểu dữ liệu union thường, nhưng ta không
cần chỉ định tên biến union mới tạo ra
union Tên_kiểu_union{
kiểu_dữ_liệu_thành_viên_1 tên_thành_viên_1;
kiểu_dữ_liệu_thành_viên_2 tên_thành_viên_2;
};
Khi khai báo biến thuộc kiểu union ẩn danh, ta có thể khai b|o như sau
Ví dụ
union Tên_kiểu_union tên_biến;
tên_biến.tên_thành_viên
Kiểu dữ liệu enum
Kiểu dữ liệu enum được tạo mới có thể chứa nhiều dữ liệu khác nhau
mà không có sự giới hạn về giá trị.
enum Tên_kiểu_enum{
giá_trị_1;
giá_trị_2;
}Tên_thể_hiện_enum;
Chúng ta có thể tham khảo thêm các ví dụ sau đ}y
enum colors{black=0, blue, green, cyan, red} mycolor;
enum colors{black=0, blue, green, cyan, red};
colors mycolor;
Enum là một loại dữ liệu chứa các biến được đ|nh chỉ số. Do đó, các giá trị
hằng của nó luôn là số nguyên (để làm chỉ số).
Chương 12. C|c kiểu dữ liệu khác
T r a n g | 119
C
+
+
Ví dụ
#include
using namespace std;
enum colors{red, green, blue};
int main()
{
for(int i=0; i<3; i++)
if (colors(i)==green) cout<<"green"<<endl;
return 0;
}
File đính kèm:
giao_trinh_lap_trinh_huong_doi_tuong_c_phan_1.pdf

