Giáo trình Lập trình hướng đối tượng (Phần 2)

Định nghĩa lớp

Cú pháp: Lớp được định nghĩa theo mẫu :class tên_lớp

{

private: [Khai báo các thuộc tính]

[Định nghĩa các hàm thành phần (phương

thức)]

public : [Khai báo các thuộc tính]

[Định nghĩa các hàm thành phần

(phương thức)]

} ;

Thuộc tính của lớp được gọi là dữ liệu thành phần và

hàm được gọi là phương thức hoặc hàm thành viên. Thuộc

tính và hàm được gọi chung là các thành phần của lớp. Các

thành phần của lớp được tổ chức thành hai vùng: vùng sở

hữu riêng (private) và vùng dùng chung (public) để quy

định phạm vi sử dụng của các thành phần. Nếu không quy

định cụ thể (không dùng các từ khóa private và public) thì

C++ hiểu đó là private. Các thành phần private chỉ được sử

dụng bên trong lớp (trong thân của các hàm thành phần).

Các thành phần public được phép sử dụng ở cả bên trong

và bên ngoài lớp. Các hàm không phải là hàm thành phần

của lớp thì không được phép sử dụng các thành phần này.

Khai báo các thuộc tính của lớp: được thực hiện y như

việc khai báo biến. Thuộc tính của lớp không thể có kiểu

chính của lớp đó, nhưng có thể là kiểu con trỏ của lớp này

pdf 154 trang kimcuc 8180
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Lập trình hướng đối tượng (Phần 2)", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Giáo trình Lập trình hướng đối tượng (Phần 2)

Giáo trình Lập trình hướng đối tượng (Phần 2)
Chương 3: Lớp
 Chương này trình bày những vấn đề sau đây:
 Định nghĩa lớp
 Tạo lập đối tượng
 Truy nhập đến các thành phần của lớp
 Con trỏ đối tượng
 Con trỏ this
 Hàm bạn
 Dữ liệu thành phần tĩnh, hàm thành phần tĩnh
 Hàm tạo, hàm hủy
 Hàm tạo sao chép
Lớp là khái niệm trung tâm của lập trình hướng đối
tượng, nó là sự mở rộng của các khái niệm cấu trúc (struct)
của C. Ngoài các thành phần dữ liệu, lớp còn chứa các
thành phần hàm, còn gọi là phương thức (method) hoặc
hàm thành viên (member function). Lớp có thể xem như
một kiểu dữ liệu các biến, mảng đối tượng. Từ một lớp đ•
định nghĩa, có thể tạo ra nhiều đối tượng khác nhau, mỗi
đối tượng có vùng nhớ riêng.
Chương này sẽ trình bày cách định nghĩa lớp, cách xây
dựng phương thức, giải thích về phạm vi truy nhập, sử
dụng các thành phần của lớp, cách khai báo biến, mảng cấu
trúc, lời gọi tới các phương thức .
3.1. Định nghĩa lớp
Cú pháp: Lớp được định nghĩa theo mẫu :
class tên_lớp
 {
 private: [Khai báo các thuộc tính]
 [Định nghĩa các hàm thành phần (phương
thức)]
 public : [Khai báo các thuộc tính]
 [Định nghĩa các hàm thành phần
(phương thức)]
 } ;
Thuộc tính của lớp được gọi là dữ liệu thành phần và
hàm được gọi là phương thức hoặc hàm thành viên. Thuộc
tính và hàm được gọi chung là các thành phần của lớp. Các
thành phần của lớp được tổ chức thành hai vùng: vùng sở
hữu riêng (private) và vùng dùng chung (public) để quy
định phạm vi sử dụng của các thành phần. Nếu không quy
định cụ thể (không dùng các từ khóa private và public) thì
C++ hiểu đó là private. Các thành phần private chỉ được sử
dụng bên trong lớp (trong thân của các hàm thành phần).
Các thành phần public được phép sử dụng ở cả bên trong
và bên ngoài lớp. Các hàm không phải là hàm thành phần
của lớp thì không được phép sử dụng các thành phần này.
Khai báo các thuộc tính của lớp: được thực hiện y như
việc khai báo biến. Thuộc tính của lớp không thể có kiểu
chính của lớp đó, nhưng có thể là kiểu con trỏ của lớp này,
Ví dụ:
class A
{
 A x; //Không cho phép, vì x có kiểu lớp A
 A *p ; // Cho phép, vì p là con trỏ kiểu lớp A
} ;
Định nghĩa các hàm thành phần: Các hàm thành phần có
thể được xây dựng bên ngoài hoặc bên trong định nghĩa
lớp. Thông thường, các hàm thành phần đơn giản, có ít
dòng lệnh sẽ được viết bên trong định nghĩa lớp, còn các
hàm thành phần dài thì viết bên ngoài định nghĩa lớp. Các
hàm thành phần viết bên trong định nghĩa lớp được viết
như hàm thông thường. Khi định nghĩa hàm thành phần ở
bên ngoài lớp, ta dùng cú pháp sau đây:
Kiểu_trả_về_của_hàm Tên_lớp::Tên_hàm(khai báo các
tham số)
 { [nội dung
hàm]
 }
Toán tử :: được gọi là toán tử phân giải miền xác định,
được dùng để chỉ ra lớp mà hàm đó thuộc vào.
 Trong thân hàm thành phần, có thể sử dụng các
thuộc tính của lớp, các hàm thành phần khác và các hàm tự
do trong chương trình.
Chú ý :
• Các thành phần dữ liệu khai báo là private nhằm
bảo đảm nguyên lý che dấu thông tin, bảo vệ an toàn dữ
liệu của lớp, không cho phép các hàm bên ngoài xâm nhập
vào dữ liệu của lớp .
• Các hàm thành phần khai báo là public có thể
được gọi tới từ các hàm thành phần public khác trong
chương trình .
3.2. Tạo lập đối tượng
Sau khi định nghĩa lớp, ta có thể khai báo các biến thuộc
kiểu lớp. Các biến này được gọi là các đối tượng. Cú pháp
khai báo biến đối tượng như sau:
 Tên_lớp Danh_sách_biến ;
Đối tượng cũng có thể khai báo khi định nghĩa lớp theo
cú pháp sau:
class tên_lớp
 {
 ...
 } ;
Mỗi đối tượng sau khi khai báo sẽ được cấp phát một
vùng nhớ riêng để chứa các thuộc tính của chúng. Không
có vùng nhớ riêng để chứa các hàm thành phần cho mỗi đối
tượng. Các hàm thành phần sẽ được sử dụng chung cho tất
cả các đối tượng cùng lớp.
3.3. Truy nhập tới các thành phần của lớp
• Để truy nhập đến dữ liệu thành phần của lớp, ta
dùng cú pháp:
 Tên_đối_tượng. Tên_thuộc_tính
Cần chú ý rằng dữ liệu thành phần riêng chỉ có thể được
truy nhập bởi những hàm thành phần của cùng một lớp, đối
tượng của lớp cũng không thể truy nhập.
• Để sử dụng các hàm thành phần của lớp, ta dùng
cú pháp:
 Tên_đối_tượng. Tên_hàm
(Các_khai_báo_tham_số_thực_sự)
Ví dụ 3.1
#include 
#include 
class DIEM
 {
 private :
 int x,y ;
 public :
 void nhapsl( )
 {
 cout << "\n Nhap hoanh do va tung do cua
diem:";
 cin >>x>>y ;
 }
 void hienthi( )
 { cout<<"\n x = " <<x<<" y = "<<y<<endl;}
 } ;
void main()
 { clrscr();
 DIEM d1;
 d1.nhapsl();
 d1.hienthi();
 getch();
 }
Ví dụ 3.2
#include 
#include 
class A
 { int m,n;
 public :
 void nhap( )
 {
 cout << "\n Nhap hai so nguyen : " ;
 cin>>m>>n ;
 }
 int max()
 { 
 return m>n?m:n;
 }
 void hienthi( )
 { cout<<"\n Thanh phan du lieu lon nhat x = "
<<max()<<endl;}
 };
void main ()
 { clrscr();
 A ob;
 ob.nhap();
 ob.hienthi();
 getch();
 }
Chú ý: Các hàm tự do có thể có các đối là đối tượng
nhưng trong thân hàm không thể truy nhập đến các thuộc
tính của lớp. Ví dụ giả sử đ• định nghĩa lớp :
class DIEM
{
 private :
 double x,y ; // toa do cua diem
 public : 
 void nhapsl()
 {
 cout << “ Toa do x,y : “ ;
 cin >> x>>y ;
 }
 void in()
 {
 cout << “x =””<<x<<”y=”<<y ;
 }
} ;
Dùng lớp DIEM, ta xây dựng hàm tự do tính độ đài của
đoạn thẳng đi qua hai điểm như sau :
 double do_dai ( DIEM d1, DIEM d2 )
 {
return sqrt(pow(d1.x-d2.x,2) + pow(d1.y-d2.y,2));
 }
 Chương trình dịch sẽ báo báo lỗi đối với hàm này.
Bởi vì trong thân hàm không cho phép sử dụng các thuộc
tính d1.x,d2.x,d1.y của các đối tượng d1 và d2 thuộc lớp
DIEM .
Ví dụ 3.3 Ví dụ sau minh họa việc sử dụng hàm thành
phần với tham số mặc định:
#include 
#include 
class Box 
{ 
 private: 
 int dai; 
 int rong; 
 int cao; 
public: 
 int get_thetich(int lth,int wdth = 2,int ht = 3); 
}; 
int Box::get_thetich(int l, int w, int h) 
{ 
 dai = l; 
 rong = w; 
 cao = h; 
 cout<< dai<<'\t'<< rong<<'\t'<<cao<<'\t'; 
 return dai * rong * cao; 
} 
void main() 
{ 
 Box ob; 
 int x = 10, y = 12, z = 15; 
 cout <<"Dai Rong Cao Thetich\n"; 
 cout << ob.get_thetich(x, y, z) << "\n"; 
 cout << ob.get_thetich(x, y) << "\n"; 
 cout << ob.get_thetich(x) << "\n"; 
 cout << ob.get_thetich(x, 7) << "\n"; 
 cout << ob.get_thetich(5, 5, 5) << "\n"; 
getch();
} 
Kết quả chương trình như sau:
Dai Rong Cao Thetich 
10 12 15 1800 
10 12 3 360 
10 2 3 60 
10 7 3 210 
5 5 5 125 
Ví dụ 3.4 Ví dụ sau minh họa việc sử dụng hàm inline
trong lớp:
#include 
#include 
#include 
class phrase 
{ 
private: 
 char dongtu[10]; 
 char danhtu[10]; 
 char cumtu[25]; 
public: 
 phrase(); 
 inline void set_danhtu(char* in_danhtu); 
 inline void set_dongtu(char* in_dongtu); 
 inline char* get_phrase(void); 
}; 
void phrase::phrase() 
{ 
 strcpy(danhtu,""); 
 strcpy(dongtu,""); 
 strcpy(cumtu,""); 
} 
inline void phrase::set_danhtu(char* in_danhtu) 
{ 
 strcpy(danhtu, in_danhtu); 
} 
inline void phrase::set_dongtu(char* in_dongtu) 
{ 
 strcpy(dongtu, in_dongtu); 
} 
inline char* phrase::get_phrase(void) 
{ 
 strcpy(cumtu,dongtu); 
 strcat(cumtu," the "); 
 strcat(cumtu,danhtu); 
 return cumtu; 
} 
void main() 
{ 
 phrase text; 
 cout " << text.get_phrase()
 << "\n"; 
 text.set_danhtu("file"); 
 cout " << 
 text.get_phrase()<<"\n"; 
 text.set_dongtu("Save"); 
 cout " <<
 text.get_phrase()<<"\n"; 
 text.set_danhtu("program"); 
 cout " <<
 text.get_phrase()<<"\n"; 
} 
Kết quả chương trình như sau:
Cum tu la : -> the 
Cum tu la : -> the file 
Cum tu la : -> Save the file 
Cum tu la : -> Save the program 
Ví dụ 3.5 Ví dụ sau minh họa việc sử dụng từ khóa
const trong lớp:
#include 
#include 
class constants
{ 
 private: 
 int number; 
 public: 
 void print_it(const int data_value); 
}; 
void constants::print_it(const int data_value) 
{ 
 number = data_value; 
 cout << number << "\n"; 
} 
void main() 
{ 
 constants num; 
 const int START = 3; 
 const int STOP = 6; 
 int index; 
 for (index=START; index<=STOP; index++) 
 { 
 cout<< "index = " ; 
 num.print_it(index); 
 cout<< "START = " ; 
 num.print_it(START); 
 } 
 getch();
} 
Kết quả chương trình như sau:
index = 3 
START = 3 
index = 4 
START = 3 
index = 5 
START = 3 
index = 6 
START = 3 
3.4. Con trỏ đối tượng
Con trỏ đối tượng dùng để chứa địa chỉ của biến đối
tượng, được khai báo như sau :
 Tên_lớp * Tên_con_ trỏ ;
Ví dụ : Dùng lớp DIEM, ta có thể khai báo:
DIEM *p1, *p2, *p3 ; // Khai báo 3 con trỏ p1, p2,
p3
DIEM d1, d2 ; //Khai báo hai đối tượng d1, d2
DIEM d [20] ; // Khai báo mảng đối tượng
Có thể thực hiện câu lệnh :
p1 = &d2 ; //p1 chứa địa chỉ của d2, p1 trỏ tới d2
p2 =d ; // p2 trỏ tới đầu mảng d
p3 =new DIEM //tạo một đối tượng và chứa địa chỉ của
nó vào p3
Để truy xuất các thành phần của lớp từ con trỏ đối
tượng, ta viết như sau :
 Tên_con_trỏ -> Tên_thuộc_tính
 Tên_con_trỏ -> Tên_hàm(các tham số thực sự)
Nếu con trỏ chứa đầu địa chỉ của mảng, có thể dùng con
trỏ như tên mảng.
Ví dụ 3.6
#include 
#include 
class mhang
 { int maso;
 float gia;
 public: void getdata(int a, float b)
 {maso= a; gia= b;}
 void show()
 { cout << "maso" << maso<< endl;
 cout << "gia" << gia<< endl;
 }
 };
const int k=5;
void main()
 { clrscr();
 mhang *p = new mhang[k];
 mhang *d = p;
 int x,i;
 float y;
 cout<<"\nNhap vao du lieu 5 mat hang :";
 for (i = 0; i <k; i++)
 { cout <<"\nNhap ma hang va don gia cho mat hang
thu " <<i+1;
 cin>>x>>y;
 p -> getdata(x,y);
 p++;}
 for (i = 0; i <k; i++)
 { cout <<"\nMat hang thu : " << i + 1 <<
 endl;
 d -> show();
 d++;
 }
 getch();
 }
3.5. Con trỏ this
Mỗi hàm thành phần của lớp có một tham số ẩn, đó là
con trỏ this. Con trỏ this trỏ đến từng đối tượng cụ thể. Ta
h•y xem lại hàm nhapsl() của lớp DIEM trong ví dụ ở trên:
 void nhapsl( )
 {
 cout << "\n Nhap hoanh do va tung do cua diem : ";
 cin >>x>>y;
 }
Trong hàm này ta sử dụng tên các thuộc tính x,y một
cách đơn độc. Điều này dường như mâu thuẩn với quy tắc
sử dụng thuộc tính. Tuy nhiên nó được lý giải như sau:
C++ sử dụng một con trỏ đặc biệt trong các hàm thành
phần. Các thuộc tính viết trong hàm thành phần được hiểu
là thuộc một đối tượng do con trỏ this trỏ tới. Như vậy hàm
nhapsl() có thể viết một cách tường minh như sau:
 void nhapsl( )
 {
 cout << "\n Nhap hoanh do va tung do cua diem:" ;
 cin >>this->x>>this->y ;
 }
Con trỏ this là đối thứ nhất của hàm thành phần. Khi một
lời gọi hàm thành phần được phát ra bởi một đối tượng thì
tham số truyền cho con trỏ this chính là địa chỉ của đối
tượng đó.
Ví dụ: Xét một lời gọi tới hàm nhapsl() :
 DIEM d1 ;
 d1.nhapsl();
Trong trường hợp này của d1 thì this =&d1. Do đó this -
> x chính là d1.x và this-> y chính là d1.y
Chú ý: Ngoài tham số đặc biệt this không xuất hiện một
cách tường minh, hàm thành phần lớp có thể có các thamô1
khác được khai báo như trong các hàm thông thường.
Ví dụ 3.7
#include 
#include 
class time
{ int h,m;
public :
void nhap(int h1, int m1)
 { h= h1; m = m1;}
void hienthi(void)
{ cout <<h << " gio "<<m << " phut"<<endl;}
void tong(time, time);
};
void time::tong(time t1, time t2)
{ m= t1.m+ t2.m; //this->m = t1.m+ t2.m;
 h= m/60; //this->h = this->m/60;
 m= m%60; //this->m = this->m%60;
 h = h+t1.h+t2.h; //this->h = this->h + t1.h+t2.h;
}
void main()
{
 clrscr();
 time ob1, ob2,ob3;
 ob1.nhap(2,45);
 ob2.nhap(5,40);
 ob3.tong(ob1,ob2);
 cout <<"object 1 = "; ob1.hienthi();
 cout <<"object 2 = "; ob2. hienthi();
 cout <<"object 3 = "; ob3. hienthi();
 getch();
}
Chương trình cho kết quả như sau :
object 1 = 2 gio 45 phut
object 2 = 5 gio 40 phut
object 3 = 8 gio 25 phut
3.6. Hàm bạn
 Trong thực tế thường x•y ra trường hợp có một số
lớp cần sử dụng chung một hàm. C++ giải quyết vấn đề này
bằng cách dùng hàm bạn. Để một hàm trở thành bạn của
một lớp, có 2 cách viết:
Cách 1: Dùng từ khóa friend để khai báo hàm trong lớp
và xây dựng hàm bên ngoài như các hàm thông thường
(không dùng từ khóa friend). Mẫu viết như sau :
 class A
 {
 private :
 // Khai báo các thuộc tính 
 public :
 ...
 // Khai báo các hàm bạn của lớp
A
 friend void f1 (...) ;
 friend double f2 (...) ;
 ...
 } ;
 // Xây dựng các hàm f1,f2,f3
 void f1 (...)
 {
 ...
 } 
 double f2 (...)
 {
 ...
 }
Cách 2: Dùng từ khóa friend để xây dựng hàm trong
định nghĩa lớp . Mẫu viết như sau :
 class A
 {
 private :
 // Khai báo các thuộc tính 
 public :
 ...
 // Khai báo các hàm bạn của lớp
A
 void f1 (...)
 {
 ...
 } 
 double f2 (...)
 {
 ...
 }
 } ;
Hàm bạn có những tính chất sau:
- Hàm bạn không phải là hàm thành phần của lớp.
- Việc truy nhập tới hàm bạn được thực hiện như hàm
thông thường.
- Trong thân hàm bạn của một lớp có thể truy nhập tới
các thuộc tính của đối tượng thuộc lớp này. Đây là sự khác
nhau duy nhất giữa hàm bạn và hàm thông thường.
- Một hàm có thể là bạn của nhiều lớp. Lúc đó nó có
quyền truy nhập tới tất cả các thuộc tính của các đối tượng
trong các lớp này. Để làm cho hàm f trở thành bạn của các
lớp A, B và C ta sử dụng mẩu viết sau :
 class B ; //Khai báo trước lớp A
 class B ; // Khai báo trước lớp B
 class C ; // Khai báo trước lớp C
 // Định nghĩa lớp A
 class A
 {
 // Khai báo f là bạn của A
 friend void f(... )
 } ;
 // Định nghĩa lớp B
 class B
 {
 // Khai báo f là bạn của B
 friend void f(...)
 } ;
 // Định nghĩa lớp C
 class C
 {
 // Khai báo f là bạn của C
 friend void f(...)
 } ;
 // Xây dựng hàm f
 void f(...)
 {
 ...
 } ;
Ví dụ 3.8
#include 
#include 
class sophuc
{float a,b;
 public : sophuc() {}
 sophuc(float x, float y)
 {a=x; b=y;}
 friend sophuc tong(sophuc,sophuc);
 friend void hienthi(sophuc);
};
sophuc tong(sophuc c1,sophuc c2)
 {sophuc c3;
 c3.a=c1.a + c2.a ;
 c3.b=c1.b + c2.b ;
 return (c3);
 }
void hienthi(sophuc c)
 {cout<<c.a<<" + "<<c.b<<"i"<<endl; }
void main()
{ clrscr();
 sophuc d1 (2.1,3.4);
 sophuc d2 (1.2,2.3) ;
 sophuc d3 ;
 d3 = tong(d1,d2);
 cout<<"d1= ";hienthi(d1);
 cout<<"d2= ";hienthi(d2);
 cout<<"d3= ";hienthi(d3);
 getch();
 }
Chương trình cho kết quả như sau :
d1= 2.1 + 3.4i
d2= 1.2 + 2.3i
d3= 3.3 + 5.7i
Ví dụ 3.9
#include 
#include 
class LOP1;
class LOP2
 {
 int v2;
 public:
 void nhap(int a)
 { v2=a;}
 void hienthi(void)
 { cout<<v2<<"\n";}
 friend void traodoi(LOP1 &, LOP2 &);
 };
class LOP1
 {
 int v1;
 public:
 void nhap(int a)
 { v1=a;}
 void hienthi(void)
 { cout<<v1<<"\n";}
 friend void traodoi(LOP1 &, LOP2 &);
 };
void traodoi(LOP1 &x, LOP2 &y)
 {
 int t = x.v1;
 x.v1 = y.v2;
 y.v2 = t;
 }
void main()
 {
 clrscr();
 LOP1 ob1;
 LOP2 ob2;
  ...  d•y ký tự (kể cả khoảng trắng) và đưa
vào vùng nhớ do str trỏ tới. Quá trình đọc kết thúc khi xảy
ra một trong hai tình huống sau:
 + Gặp ký tự giới hạn (cho trong d). Ký tự giới hạn mặc
định là ‘\n’.
 + Đ• nhận đủ (n-1) ký tự.
Chú ý:
 + Ký tự kết thúc chuỗi ‘\0’ được bổ sung vào cuối
chuối nhận được.
 + Ký tự giới hạn vẫn còn lại trên dòng nhập để dành
cho các lệnh nhận tiếp theo.
 + Ký tự còn lại trên dòng nhập có thể làm trôi
phương thức get() dạng 3. Ví dụ: Xét đoạn chương trình:
 char hoten[25], diachi[50], quequan[30] ;
 cout<<”\nHọ tên:”;
 cin.get(ht,25);
 cout<<”\nĐịa chỉ : ”;
 cin.get(diachi,50);
 cout<<”\nQuê quán : ”;
 cin.get(quequan,30);
 cout <<”\n” <<hoten<<” ”<<diachi<<” ”<<quequan;
 Đoạn chương trình dùng để nhập họ tên, dịa chỉ và quê
quán. Nếu gõ vào Nguyen van X thì câu lệnh get
đầu tiên sẽ nhận được chuỗi “Nguyen van X” cất vào mảng
hoten. Ký tự còn lại sẽ làm trôi 2 câu lệnh get tiếp
theo. Do đó câu lệnh cuối cùng sẽ chỉ in ra Nguyen van X.
 Để khắc phục tình trạng trên, có thể dùng một trong các
cách sau:
 + Dùng phương thức get() dạng 1 hoặc dạng 2 để lấy ra
ký tự trên dòng nhập trước khi dùng get (dạng 3).
 + Dùng phương thức ignore để lấy ra một số ký tự
không cần thiết trên dòng nhập trước khi dùng get dạng 3.
Phương thức này viết như sau:
 cin.ignore(n) ; // Lấy ra (loại ra hay loại bỏ) n ký tự
trên dòng nhập.
Như vậy để có thể nhập được cả quê quán và cơ quan,
cần sửa lại đoạn chương trình trên như sau:
 char hoten[25], diachi[50], quequan[30] ;
 cout<<”\nHọ tên : ”;
 cin.get(hoten,25);
 cin.get(); // Nhấn 
 cout<<”\nĐịa chỉ : ”;
 cin.get(diachi,50);
 ignore(1); // Bỏ qua 
 cout<<”\nQuê quán : ”;
 cin.get(quequan,30);
 cout <<”\n” <<hoten<<” ”<<diachi<<” ”<<quequan;
1.3.2. Phương thức getline()
Phương thức getline để nhập một d•y ký tự từ bàn phím,
được mô tả như sau:
 istream& cin.getline(char *str, int n, char d = ‘\n’);
Ví dụ:
 char hoten[25], diachi[50];
 cout<<”\nHọ tên:”;
 cin.getline(hoten,25);
 cout<<”\nĐịa chỉ”;
 cin.getline(diachi,50);
 cout <<”\n” <<hoten<<” ”<<diachi;
1.3.3. Phương thức ignore
Phương thức ignore dùng để bỏ qua (loại bỏ) một số ký
tự trên dòng nhập. Trong nhiều trường hợp, đây là việc làm
cần thiết để không làm ảnh hưởng đến các phép nhập tiếp
theo. Phương thức ignore được mô tả như sau:
 istream& cin.ignore(int n=1);
 Phương thức sẽ bỏ qua (loại bỏ) n ký tự trên dòng
nhập.
1.4. Dòng cout và toán tử xuất <<
1.4.1. Dòng cout
 cout là một đối tượng kiểu ostream và được nói là “bị
ràng buộc tới”thiết bị chuẩn, thông thường là màn hình.
Các thao tác xuất trên dòng cout đồng nghĩa với xuất dữ
liệu ra màn hình.
1.4.2. Toán tử xuất <<
 C++ định nghĩa chồng toán tử dịch trái << để gửi các
ký tự sang dòng xuất .
 Cách dùng toán tử xuất để xuất dữ liệu từ bộ nhớ ra
dòng cout như sau:
 cout<<biểu thức;
Trong đó biểu thức biểu thị một giá trị cần xuất ra màn
hình. Giá trị sẽ được biến đổi thành một d•y ký tự trước khi
đưa ra dòng xuất.
Chú ý: Để xuất nhiều giá trị trên một dòng lệnh, có thể
viết như sau:
cout<<biểu thức 1<<biểu thức 2 <<...<<biểu thức n;
1.4.3. Các phương thức định dạng
1. Phương thức int cout.width();
cho biết độ rộng quy định hiện tại.
2. Phương thức int cout.width(int n);
thiết lập độ rộng quy định mới là n và trả về độ rộng quy
định trước đó.
Chú ý: Độ rộng quy định n chỉ có tác dụng cho một giá
trị xuất. Sau đó C++ lại áp dụng độ rộng quy định bằng 0.
Ví dụ với các câu lệnh:
 int m=1234, n=56;
 cout<<”\nAB”;
 cout.width(6);
 cout<<m;
 cout<<n;
thì kết quả là:
 AB 123456
 (giữa B và số 1 có 2 dấu cách).
3. Phương thức int cout.precision();
cho biết độ chính xác hiện tại (đang áp dụng để xuất các
giá trị thức).
4. Phương thức int cout.precision(int n);
thiết lập dộ chính xác sẽ áp dụng là n và cho biết độ
chính xác trước đó. Độ chính xác được thiết lập sẽ có hiệu
lực cho tới khi gặp một câu lệnh thiết lập độ chính xác mới.
5. Phương thức char cout.fill();
cho biết ký tự độn hiện tại đang được áp dụng.
6. Phương thức char cout.fill( char ch);
quy định ký tự độn mới sẽ được dùng là ch và cho biết
ký tự độn đang dùng trước đó. Ký tự độn được thiết lập sẽ
có hiệu lực cho tới khi gặp một câu lệnh chọn ký tự độn
mới.
Ví dụ:
#include 
#include 
void main()
 {
 clrscr();
 float x=-3.1551, y=-23.45421;
 cout.precision(2);
 cout.fill(‘*’);
 cout<<”\n”;
 cout.width(8);
 cout<<x;
 cout<<”\n”;
 cout.width(8);
 cout<<y;
 getch();
 }
 Sau khi thực hiện, chương trình in ra màn hình 2 dòng
sau:
 ***-3.16
 **-23.45
1.4.4. Cờ định dạng
Mỗi cờ định dạng chứa trong một bit. Cờ có 2 trạng
thái: Bật (on) – có giá trị 1, Tắt (off) – có giá trị 0. Các cờ
có thể chứa trong một biến kiểu long. Trong tập tin 
iostream.h đ• định nghĩa các cờ sau:
 ios::left ios::right 
ios::internal 
 ios::dec ios::oct ios::hex
 ios::fixed ios::scientific 
ios::showpos
 ios::uppercase ios::showpoint 
ios::showbase
Có thể chia cờ định dạng thành các nhóm:
 Nhóm 1 gồm các cờ căn lề:
 ios::left ios::right ios::internal
 Cờ ios::left: khi bật cờ ios::left thì giá trị in ra nằm bên
trái vùng quy định, các ký tự độn nằm sau.
 Cờ ios::right: khi bật cờ ios::right thì giá trị in ra nằm
bên phải vùng quy định, các ký tự độn nằm trước.
 Chú: ý mặc định cờ ios::right bật.
 Cờ ios::internal: cờ ios::internal có tác dụng giống như
cờ ios::right chỉ khác là dấu (nếu có) in đầu tiên.
 Chương trình sau minh hoạ cách dùng các cờ căn lề:
Ví dụ
#include 
#include 
void main()
 {
 clrscr();
 float x=-87.1551, y=23.45421;
 cout.precision(2);
 cout.fill('*');
 cout.setf(ios::left); //bat co ios::left
 cout<<"\n";
 cout.width(8);
 cout<<x;
 cout<<"\n";
 cout.width(8);
 cout<<y;
 cout.setf(ios::right); //bat co ios::right
 cout<<"\n";
 cout.width(8);
 cout<<x;
 cout<<"\n";
 cout.width(8);
 cout<<y;
 cout.setf(ios::internal); //bat co ios::internal
 cout<<"\n";
 cout.width(8);
 cout<<x;
 cout<<"\n";
 cout.width(8);
 cout<<y;
 getch();
 }
 Sau khi thực hiện chương trình in ra 6 dòng như sau:
 -87.16**
 23.45**
 **-87.16
 ***23.45
 -**87.16
 ***23.45
 Nhóm 2 gồm các cờ định dạng số nguyên:
 ios::dec ios::oct ios::hex
 + Khi ios::dec bật (mặc định): số nguyên được in dưới
dạng cơ số 10
 + Khi ios::oct bật: số nguyên được in dưới dạng cơ số 8
 + khi ios::hex bật: số nguyên được in dưới dạng cơ số
16
 Nhóm 3 gồm các cờ định dạng số thực:
 ios::fixed ios::scientific 
 ios::showpoint
 Mặc định : cờ ios::fixed bật (on) và cờ ios::showpoint
tắt (off).
 + Khi ios::fixed bật và cờ ios::showpoint tắt thì số thực
in ra dưới dạng thập phân, số chữ số phần phân (sau dấu
chấm) được tính bằng độ chính xác n nhưng khi in thì bỏ đi
các chữ số 0 ở cuối.
 Ví dụ nếu độ chính xác n = 4 thì
 Số thực -87.1500 được in: -87.15
 Số thực 23.45425 được in: 23.4543
 Số thực 678.0 được in: 678
 + Khi ios::fixed bật và cờ ios::showpoint bật thì số thực
in ra dưới dạng thập phân, số chữ số phần phân (sau dấu
chấm) được in ra đúng bằng độ chính xác n. 
 Ví dụ nếu độ chính xác n = 4 thì
 Số thực -87.1500 được in: -87.1500
 Số thực 23.45425 được in: 23.4543
 Số thực 678.0 được in: 6780000
 + Khi ios::scientific bật và cờ ios::showpoint tắt thì
số thực in ra dưới dạng khoa học. Số chữ số phần phân (sau
dấu chấm) được tính bằng độ chính xác n nhưng khi in thì
bỏ đi các chữ số 0 ở cuối.
 Ví dụ nếu độ chính xác n=4 thì
 Số thực -87.1500 được in: -87.15e+01
 Số thực 23.45425 được in: 23.4543e+01
 Số thực 678.0 được in: 678e+02
 + Khi ios::scientific bật và cờ ios::showpoint bật thì
số thực in ra dưới dạng mũ . Số chữ số phần phân (sau dấu
chấm) của phần định trị được in đúng bằng độ chính xác n.
 Ví dụ nếu độ chính xác n=4 thì
 Số thực -87.1500 được in: -87.150e+01
 Số thực 23.45425 được in: 23.4543e+01
 Số thực 678.0 được in: 67800e+01
 Nhóm 4 gồm các hiển thị:
 ios::uppercase ios::showpos ios::showbase
 Cờ ios::showpos
 + Nếu cờ ios::showpos tắt (mặc định) thì dấu cộng
không được in trước số dương.
 + Nếu cờ ios::showpos tắt thì dấu cộng được in trước
số dương.
 Cờ ios::showbase bật thì số nguyên hệ 8 được in bắt đầu
bằng ký tự 0 và số nguyên hệ 16 được bắt đầu bằng các ký
tự 0x. Ví dụ nếu a = 40 thì:
 Dạng in hệ 8 là: 050
 Dạng in hệ 16 là 0x28
 Cờ ios::showbase tắt (mặc định) thì không in 0 trước số
nguyên hệ 8 và không 0x trước số nguyên hệ 16. Ví dụ nếu
a = 40 thì:
 Dạng in hệ 8 là: 50
 Dạng in hệ 16 là 28
 Cờ ios::uppercase
 + Nếu cờ ios::uppercase bật thì các chữ số hệ 16 (như
A, B, C,...) được in dưới dạng chữ hoa.
 + Nếu cờ ios::uppercase tắt (mặc định) thì các chữ số
hệ 16 (như A, B, C,...) được in dưới dạng chữ thường.
1.4.5. Các phương thức bật tắt cờ
 Các phương thức này định nghĩa trong lớp ios.
1. Phương thức long cout.setf(long f) ;
sẽ bật các cờ liệt kê trong f và trả về một giá trị long
biểu thị các cờ đang bật.
2. Phương thức long cout.unsetf(long f) ;
 sẽ tắt các cờ liệt kê trong f và trả về một giá trị long
biểu thị các cờ đang bật. 
3. Phương thức long cout.flags(long f) ;
có tác dụng giống như cout.setf(long).
4. Phương thức long cout.flags() ;
sẽ trả về một giá trị long biểu thị các cờ đang bật.
1.4.6. Các bộ phận định dạng
 Các bộ phận định dạng (định nghĩa trong tập tin
iostream.h) bao gồm:
 dec // như cờ ios::dec
 oct // như cờ ios::oct
 hex // như cờ ios::hex
 endl // xuất ký tự ‘\n’ (chuyển dòng)
 flush // đẩy dữ liệu ra thiết bị xuất
Ví dụ Xét chương trình sau:
#include 
#include 
#include 
void main()
 {
 clrscr();
 cout.setf(ios::showbase);
 cout<<”ABC”<<endl<<hex<<40<<” ”<<41;
 getch();
 }
1.4.7. Các hàm định dạng
 Các hàm định dạng (định nghĩa trong ) 
bao gồm:
 set(int n) // như cout.width(int n)
 setpecision(int n) // như cout.setpecision(int n)
 setfill( char ch) // như cout.setfill( char ch)
 setiosflags( long l) // như cout. setiosflags( long f)
 resetiosflags( long l) // như cout. setiosflags( long f)
Các hàm định dạng có tác dụng như các phương thức
định dạng nhưng được viết nối đuôi trong toán tử xuất nên
tiện sử dụng hơn.
 Chú ý
 Các hàm định dạng ( cũng như các bộ phận định
dạng ) cần viết trong toán tử xuất. Một hàm định dạng đứng
một mình như một câu lệnh sẽ không có tác dụng dịnh
dạng.
 Muốn sử dụng các hàm định dạng cần bổ sung vào
đầu chương trình câu lệnh: #include 
Chương trình trong ví dụ 1.2. có thể viết lại theo các
phương án sau:
Phương án 1:
#include 
#include 
void main()
 {
 clrscr();
 cout <<setiosflags(ios::showbase);
 cout<<”ABC”<<endl<<hex<<40<<” “<<41;
 getch();
 }
 Phương án 2:
#include 
#include 
void main()
 {
 clrscr();
 cout <<”ABC”<<endl<< setiosflags(ios::showbase)
 << hex<<40<<” “<<41;
 getch();
 }
1.5. Các dòng chuẩn
 Có 4 dòng (đối tượng của các lớp stream) đ• định nghĩa
trước, được cài đặt khi chương trình khởi động là:
 - cin dòng input chuẩn gắn với bàn phím, giống
như stdin của C.
- cout dòng output chuẩn gắn với màn hình, giống như
stdout của C.
- cerr dòng output lỗichuẩn gắn với màn hình, giống như
stderr của C.
- clog giống cerr nhưng có thêm bộ đệm.
 Chú ý
 Có thể dùng các dòng cerr và clog để xuất ra màn
hình như đ• dùng đối với cout.
 Vì clog có thêm bộ đệm, nên dữ liệu được đưa vào
bộ đệm. Khi đầy bộ đệm thì đưa dữ liệu bộ đệm ra dòng
clog. Vì vậy trước khi kết thúc xuất cần dùng phương thức:
clog.flush(); để đẩy dữ liệu từ bộ đệm ra clog.
Chương trình sau minh họa cách dùng dòng clog. Chúng
ta nhận thấy, nếu bỏ câu lệnh clog.flush() thì sẽ không nhìn
thấy kết quả xuất ra màn hình khi chương trình tạm dừng
bởi câu lệnh getch().
Ví dụ
#include 
#include 
void main()
 {
 clrscr();
 float x=-87.1500, y=23.45425,z=678.0;
 clog.setf(ios::scientific);
 clog.precision(4);
 clog.fill('*');
 clog<<"\n";
 clog.width(10);
 clog<<x;
 clog<<"\n";
 clog.width(10);
 clog<<y;
 clog<<"\n";
 clog.width(10);
 clog<<z;
 clog.flush();
 getch();
 }
1.6. Xuất ra máy in
Bốn dòng chuẩn không gắn với máy in. Như vậy không
thể dùng các dòng này để xuất dữ liệu ra máy in. Để xuất
dữ liệu ra máy in (cũng như nhập, xuất trên tệp) cần tạo ra
các dòng tin mới và cho nó gắn với thiết bị cụ thể. C++
cung cấp 3 lớp stream để làm điều này, đó là các lớp:
 ofstream dùng để tạo các dòng xuất (ghi tệp)
 ifstream dùng để tạo các dòng nhập (độc tệp)
 fstream dùng để tạo các dòng nhập, dòng xuất
hoặc dòng nhập-xuất
Mỗi lớp có 4 hàm tạo dùng để khai báo các dòng (đối
tượng dòng tin). Để tạo một dòng xuất và gắn nó với máy
in ta có thể dùng một trong những hàm tạo sau đây:
 ofstream Tên_dòng(int fd);
 ofstream Tên_dòng(int fd, chả *buf, int n);
Trong đó:
 - Tên_dòng là tên biến đối tượng kiểu ofstream
chúng ta tự đặt.
 - fd(file disciptor) là chỉ số tập tin. Chỉ số tập tin
định sẵn đối với stdprn (máy in chuẩn) là 4.
 - Các tham số buf và n xác định một vùng nhớ n
byte do buff trỏ tới. Vùng nhớ sẽ được làm bộ đệm cho
dòng xuất.
Ví dụ: Câu lệnh ofstream prn(4); sẽ tạo dòng tin xuất prn
và gắn nó với máy in chuẩn. Dòng prn sẽ có bộ đệm mặc
định. Dữ liệu trước hết chuyển vào bộ đệm, khi đầy bộ đêm
thì dữ liệu sẽ được đẩy từ bộ đệm ra dòng prn và có thể sử
dụng phương thức flush hoặc bộ phận định dạng flush.
Cách viết như sau:
 prn.flush ;// Phương thức
 prn<<flush; //Bộ phận định dạng
Các câu lệnh sau sẽ xuất dữ liệu ra prn (máy in) và ý
nghĩa của chúng như sau:
 prn<<”\n Tong=”<<(4+9); //Đưa một dòng vào bộ
đệm
 prn<<”\n Tich=”<<(4*9); // Đưa dòng tiếp theo
vào bộ đệm
 prn.flush(); //Đẩy dữ liệu từ bộ đệm ra máy in (in
2 dòng)
Các câu lệnh dưới đây sẽ xuất dữ liệu ra máy in nhưng
xuất từng dòng một:
 prn<<”\n Tong=”<<(4+9)<<flush; // In một dòng
 prn<<”\n Tích=”<<(4*9)<<flush; //In dòng tiếp
theo
Ví dụ: Các câu lệnh
 char buf [512];
 ofstream prn(4,buf,512);
sẽ tạo dòng tin xuất prn và gắn nó với máy in chuẩn.
Dòng xuất prn sử dụng 512 byte của mảng buf làm bộ đệm.
Các câu lệnh dưới đây cũng xuất ra máy in:
 prn<<”\n Tong=”<<(4+9); //Đưa dữ liệu vào bộ
đêm
 prn<<”\n Tich=”<<(4*9) ; //Đưa dữ liệu vào bộ
đêm
 prn.flush(); // Xuất 2 dòng (ở bộ đệm) ra máy in
Chú ý: Trước khi kết thúc chương trình, dữ liệu từ bộ
đệm sẽ được tự động đẩy ra máy in.
Tài liệu tham khảo
1. Ivar Jacobson, Object - Oriented Software
Engineering, Addison-Wesley Publishing Company, 1992.
2. Michael Blaha, William Premerlani, Object - Oriented
Modeling and Design for Database Applications, Prentice
Hall, 1998.
2. Phạm Văn ất, C++ và Lập trình hướng đối tượng,
NXB Khoa học và Kỹ thuật, 1999.
3. Đoàn Văn Ban, Phân tích và thiết kế hướng đối tượng,
NXB Khoa học và Kỹ thuật, 1997.
4. Nguyễn Thanh Thủy, Lập trình hướng đối tượng với
C++, NXB Khoa học và Kỹ thuật, 1999.

File đính kèm:

  • pdfgiao_trinh_lap_trinh_huong_doi_tuong_phan_2.pdf