610 likes | 786 Views
Chương 3 Hỗ trợ cơ bản về OOP của Borland C++. Mục tiêu. Đến cuối chương, bạn có thể: Nhận dạng được những khác biệt giữa C chuẩn và C++. Định nghĩa được lớp và sử dụng đối tượng thuộc lớp. Biết nhập xuất dữ liệu cơ bản với đối tượng cin, cout. Biết cách viết chương trình OOP với C++.
E N D
Mục tiêu Đến cuối chương, bạn có thể: Nhận dạng được những khác biệt giữa C chuẩn và C++. Định nghĩa được lớp và sử dụng đối tượng thuộc lớp. Biết nhập xuất dữ liệu cơ bản với đối tượng cin, cout. Biết cách viết chương trình OOP với C++.
Nội dung 3.1- Ôn tập 3.2- Khác biệt giữa C chuẩn và C++. 3.3- Cú pháp khai báo lớp của C++. 3.4- Nhập xuất dữ liệu cơ bản với cin, cout 3.5- Kỹ thuật xây dựng class. 3.6- Một số chương trình OOP thí dụ.
3.1- Ôn tập • Lớp = Dữ liệu + Hành vi. • Hành vi public: Hành vi giao tiếp của đối tượng thuộc lớp với môi trường. • Hành vi private: Hành vi nội của đối tượng thuộc lớp. Môi trường bên ngoài không được phép truy cập. • Thừa kế: Kỹ thuật cho phép tái sử dụng thông tin. Lớp con = Lớp cha + các thành phần riêng riêng. • Đa hình: Kỹ thuật cho phép thay nội dung (code) của 1 hành vi làm cho các đối tượng sẽ ứng xử khác nhau dù cùng tên hành vi. • Bao gói dữ liệu: Hiện thực 1 lớp gồm dữ liệu + hành vi.
3.2- Khác biệt giữa C chuẩn và C++ C++ là tập bao của C chuẩ. Tuy nhiên, có một số khác biệt về: • Từ khóa. • Chú thích. • Ép kiểu. • Khai báo và sử dụng struct. • Prototype hàm. • Chỉ thị const. • void pointer. • Toán tử sizeof • Toán tử new và delete. • Hạn chế của phát biểu goto. • Hàm với tham số mặc định. • Hàm trùng tên (overloaded functions). • Hàm inline. • Tham số của hàm là alias của một dữ liệu.
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt về chú thích: C chuẩn : /* Chú thích có thể nhiều dòng */ C++ : /* Chú thích có thể nhiều dòng */ // chú thích đến hết dòng
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt ép kiểu: C chuẩn : C++: double x= 5.345; double x= 5.345; int n = (int) x; int n = (int) x; // hoặc int n= int(x);
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt khai báo và sử dụng struct: C chuẩn : C++: struct Node struct Node { struct Node *Next; { Node *Next; void *info ; void *info ; } ; }; struct Node aNode ; Node aNode;
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt về prototype hàm: C chuẩn : C++: #include <stdio.h> main() void main() { printf (“Hello!\n”); { printf (“Hello!\n”); } } C chuẩn cho phép vì hàm không prototype sẽ có kiểu trả trị mặc định là int còn trong C++ có tính định kiểu cao, buộc phải prototype hàm trước khi dùng. Khai báo trong C char *malloc() ; /* Đối số trống, C hiểu là không đối số hoặc là đối số thay đổi */ Khi dùng int *raw_data ; raw_data = (int *) malloc (1024) ; Điều này được chấp nhận trong C nhưng không được chấp nhận trong C++ vì khi hàm không đối số thì C++ hiều là void.
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt chỉ thị const: C chuẩn không đòi hỏi phải khởi tạo trị cho dữ liệu đi sau chỉ thị const C++ đòi hỏi phải khởi tạo trị cho dữ liệu đi sau chỉ thị const Thí dụ: const buf_len ; // C chấp nhận, C++ không chấp nhận const buf=512; // C, C++ đều chấp nhận const int Max=100; // C, C++ đều chấp nhận C++ cho phép 1 tên hằng số nguyên làm chỉ số cho mảng, còn C chuẩn thì không . Thí dụ Trong C Trong C++ #define EOF -1 const EOF= -1; #define Pi 3.141592 const double Pi=3.141592 ; #define buflen 512 const buflen =512 ; char buffer [buflen]; char buffer [buflen]; ( C++ cho phép sử dụng cú pháp C chuẩn khi định nghĩa mảng thông qua hằng với chỉ thị define)
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt về sử dụng void pointer: C cho phép gán void pointer cho 1 pointer có kiểu. C++ đòi hỏi phải ép kiểu tường minh khi gán void pointer cho 1 pointer có kiểu Thí dụ: void *pvoid ; int i , *p_i ; pvoid = & i ; // Cho phép trong C và C++ p_i = pvoid ; // Cho phép trong C - Không cho phép trong C++ p_i = (int *) pvoid ; // ép kiểu tường minh cho phép trong C++
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt về kiểu trả trị của toán tử sizeof: sizeof (‘Q’) : Trong C : trả trị sizeof (int) Trong C++ : trả trị sizeof (char) sizeof(biến enum) : Trong C : trả trị sizeof (int) Trong C++ : trả trị khác sizeof (int) C++ mang tính định kiểu cao hơn C chuẩn
Khác biệt giữa C chuẩn và C++ (tt) Khác biệt về phát biểu goto: Trong C : Cho phép dùng phát biểu goto Label; Trong C++ : Không cho phép dùng phát biểu goto Lý do: Vì có thể nhẩy vào 1 phát biểu giữa 1 khối bỏ qua các phát biểu đầu khối Có thể truy xuất 1 biến mà chưa định nghĩa biến này Lỗi run-time.
Khác biệt giữa C chuẩn và C++ (tt) Toán tử new và delete chỉ có trong C++: Trong C Trong C++ #include <alloc.h> #include <iostream.h> #include <stdio.h> void main () main() { float *a= new float ; { float *a ; *a= 3.14159269; a=(float *) malloc (sizeof(float)); cout << *a ; *a=3.14159269; delete a; printf (“%f\n”, *a); } free (a); } Cấp phát động 1 mảng Trong C Trong C++ #include <alloc.h> float *a= new float [100]; float *a ; hoặc a=(float *) malloc (100* sizeof(float)); float *a = new float [100]; Khi trả bộ nhớ 1 mảng động: delete [ ] a;
Khác biệt giữa C chuẩn và C++ (tt) Hàm với đối số mặc định chỉ có trong C++: // Hàm tạo 1 cửa số : window create_window (int x=0,int y=0,int width=100, int height=50,int bgpixel=0) { <code> } Sử dụng: window w1,w2,w3; // Định nghĩa 3 cửa sổ // cửa sổ w1 có các thuộc tính mặc định w1=create_window(); // cửa sổ w2 được ấn định 5 thuộc tính w2=create_window(100,0,100,50,0); // cửa sổ w3 có 3 thuộc tính cuối có trị mặc định w3=create_window(30,20);
Khác biệt giữa C chuẩn và C++ (tt) Hàm trùng tên (overloaded function) chỉ có trong C++: C++ cho phép các hàm cùng tên nhưng khác tham số vì đủ phân biệt các hàm. C chuẩn cần 3 tên hàm lấy trị tuyệt đối int abs (int); long labs (long); double fabs (double) . C++ chỉ cần 1 tên hàm int abs (int) long abs (long) double abs (double) Lợi ích của overloaded functions Người lập trình bớt phải nhớ. Càng nhiều tên càng rối khi sử dụng.
Khác biệt giữa C chuẩn và C++ (tt) Hàm inline trong C++: • Dùng macro cho các tác vụ đơn giản dễ gây lỗi logic khó kiểm soát (hiệu ứng lề của macro,side effect). Thí dụ: # define multiply (x,y) (x*y) Sử dụng: x= multiply(4+1 , 6) ; Kết qủa sai vì khi thay macro: x=(4+1*6); // kết qủa x = 10, sai • Cách hiệu chỉnh: (1) Bao đối số trong macro (2)Dùng hàm inline # define multiply (x,y) (x)*(y) inline int multiply (int x,int y) x=(4+1)*(6); // đúng { return x * y ; } inline double multiply (double x , double y) { return x * y ; } Cơ chế làm việc của hàm inline: Trình biên dịch sẽ thay thế ruột hàm vào nơi gọi nó Giống macro, nhưng tránh được hiệu ứng lề, tối ưu thời gian Chỉ hiện thực các hàm inline cho các tác vụ đơn, không có các phát biểu lặp hoặc switch.
Khác biệt giữa C chuẩn và C++ (tt) Alias trong tham số của hàm: • C chuẩn chỉ hỗ trợ tham trị cho hàm Muốn thay đổi biến phải dùng pointer . Thí dụ: void Swap (int* pa, int* pb) { int t= *pa; &*pa=*pb; *pb=t; } Sử dụng: int a=5, b=7; Swap (&a, &b); • C++ hỗ trợ alias của 1 biến là tham số của hàm Truy xuất alias chính là truy xuất biến Muốn thay đổi biến nên dùng alias trong tham số của hàm. Thí dụ: void Swap (int &a, int &b) { int t= a; a=b; b=t; } Sử dụng: int m=5, n=7; Swap (m,n);
3.3- Hiện thực class trong C++ 3.3.1- Khai báo class. 3.3.2- Hiện thực hành vi cho class. 3.3.3- Sử dụng class trong chương trình.
3.3.1-Khai báo class class ClassName [: [<public|private>] <FatherClassName,] { public : < data > <method> private : < data > < method> protected : < data > <method> } ; // có ký tự ‘;’ • Chương này tạm không đề cập đến đặc tính thừa kế - Có chương riêng về tính thừa kế. • Các modifier: public, private, protected: từ khóa chỉ định đặc tính của từng thành phần ngay sau chỉ thị này. Mặc định là private. • public: cho phép bên ngoài truy cập interface của lớp. • private: các thành phần nội, không cho phép bên ngoài truy cập. • protected: các thành phần dành cho lớp thừa kế truy cập, không cho phép các đối tượng không phải là con truy cập.
3.3.2- Hiện thực hành vi cho class • Hiện thực bên trong class – Các hành vi inline Không dùng các phát biểu continue , do , for , goto , switch , case , break , while. Cú pháp: DataType MethodName (Parameters) { <code> } • Hiện thực bên ngoài class DataType ClassName::MethodName (Parameters) { <code> } • Toán tử :: là toán tử xác định tầm vực của method (scope resolution operator)
Demo OK Khi hiện thực method bên ngoài class, KHÔNG khai báo lại access-specifier.
3.3.3- Sử dụng class • Sử dụng class trong chương trình là định nghĩa biến đối tượng (biến tĩnh, biến động, mảng tĩnh, mảng động) • Cú pháp: ClassName Obj, *pObj = new ClassName; ClassName ObjArr1[100]; ClassName * ObjArr2; int MaxCount=100; ObjArr2= new ClassName[MaxCount]; Truyền thông báo cho 1 đối tượng: Obj.Method1(); pObj -> Method2(); ObjArr1[20].Method3(); ObjArr2[7].Method4();
3.4- Nhập xuất dữ liệu cơ bản với cin, cout,cerr • Khi hiện thực các hành vi của đối tượng, chúng ta thường cần xuất nhập dữ liệu cho các thuộc tính của đối tượng ( properties). • Trong thư viện iostream.h của C++, định nghĩa sẵn các đối tượng cho việc nhập xuất các dữ liệu cơ bản: cin, cout, cerr. • cin : (character input) Đối tượng nhập mặc định là bàn phím. • cout: (character output): Đối tượng xuất mặc định là màn hình. • cerr: (character error): Đối tượng xuất lỗi mặc định là màn hình.
3.4.1- Nhập dữ liệu cơ bản với cin Cú pháp: cin >> var1 >> var2 >> var3; Thí dụ: int m; double x; char c1; char s1[20]; cin>> m >> x >> c1 >> s1; Dạng nhập: 5 5.407 A Hello • Toán tử >> là toán tử trích, dữ liệu vào các biến theo thứ tự: trái phải. • Toán tử >> tự động kiểm tra kiểu của biến. • Toán tử >> chỉ chấp nhận chuỗi không có khoảng trống (tương tự hàm scanf). Việc nhập chuỗi có khoảng trống sẽ bàn đến trong chương sau.
3.4.2- Xuất dữ liệu cơ bản với cout Cú pháp: cout << Data1 << Data2<< Data3 ; Thí dụ: int m=7; double x=0.5; cout <<“Hello “ <<‘A’ <<m <<‘ ‘<<x <<‘\n’; Sẽ xuất: Hello A 7 0.5 - • Toán tử << là toán tử chèn, dữ liệu xuất theo thứ tự: trái phải. • Toán tử << tự động kiểm tra kiểu của biến. • Toán tử << cho phép xuất chuỗi có khoảng trống (tương tự hàm printf) . Việc định dạng độ dài xuất sẽ bàn đến trong chương sau.
3.4.3- Xuất dữ liệu cơ bản với cerr Cú pháp giống cout vì cùng là màn hình: cerr << Data1 << Data2<< Data3 ; • Không có gì khác biệt khi xuất dữ liệu cơ bản giữa cout và cerr. • Thường dùng cerr trong chương trình khi cố tình muốn nhấn mạnh những đoạn xử lý tình huống lỗi.
3.5- Gợi ý về xây dựng chương trình OOP Xây dựng class (1) Nhặt ra các khái niệm liên quan đến bài toán (danh từ chính trong đề bài) để xây dựng thành class (thí dụ: Sinh viên). (2) Nhặt ra các danh từ mô tả liên quan đến từng khaí niệm ở bước (1). Đó chính là các thuộc tính của class( thí dụ: tên, tuổi, địa chỉ). (3) Nhặt ra các tác vụ phải xử lý (động từ trong đề bài). Đó chính là các hành vi public của class vì hàm main cần đến chúng. (4) Tự hỏi: Để có thể thực hiện hành vi public trong bước 3, có cần thêm các hành vi phụ trợ nào không? Nếu có thì đó là hành vi thêm. (5) Môi trường bên ngoài thực sự chỉ cần các hành vi nào thì đó là các hành vi public. Các hành vi còn lại là các hành vi private hoặc protected. (5) Liệu lớp này có cần được phát triển thêm để giải các bài toán thuộc nhóm bài toàn này nữa hay không? Nếu có thì một số hành vi cần có thuộc tính protected.
Kinh nghiệm Mỗi thuộc tính của class, người ta thường xây dựng 2 hành vi public: DataType getPropertyName(); void setProperTyName (DataType newValue); Với 2 hành vi này, bên ngoài truy xuất được từng thuộc tính của đối tượng. Các hành vi khác đều cần đến các hành vi này.
Thí dụ: class CIRCLE { double x,y,r; public: ...... double getR() { return r ; } void setR (double newr) { if ( newr >=0 ) r = newr ; } .... }; Có cơ hội kiểm tra dữ liệu đầu vào
Sử dụng class trong hàm main • Xác định các biến đối tượng cần có. • Trật tự xử lý của đề bài chính là trật tự truyền thông báo cho các đối tượng.
3.6- Một số thi dụ • Viết chương trình nhập 1 hệ phương trình bậc nhất 2 ẩn. Xuất nghiệm. • Viết chương trình nhập 1 mảng số nguyên, xuất trị lớn nhất, xuất mảng tăng dần.
Thí dụ:Viết chương trình nhập 1 hệ phương trình bậc nhất 2 ẩn.Xuất nghiệm. Phân tích: • Khái niệm liên quan: Hệ phương trình bậc nhất 2 ẩn ax+by = c class HPTB1 dx+ey = f • Tác vụ (hành vi của lớp): Nhập, Xuất nghiệm. • class HPTB1 data: double a,b,c,d,e,f methods: Nhap() , XuatNghiem()
#include <conio.h> #include <iostream.h> class HPTB1 { double a,b,c,d,e,f ; // private , default public :// các hành vi bên ngoài cần để tương tác void Nhap()// Hiện thực method bên trong khai báo class { cout << "Nhap 3 he so a,b,c cua phuong trinh 1 ax+by=c :"; cin>>a>>b>>c; cout << "Nhap 3 he so d,e,f cua phuong trinh 2 dx+ey=f :"; cin>>d>>e>>f; } void XuatNghiem();// chỉ prototype, để hiện thực bên ngoài khia báo class }; void PTB1::XuatNghiem()// Hiện thực method bên ngoài khai báo class { double D=a*e-b*d; if (D==0) cout<< "Vo nghiem"; else cout<< "Nghiem x=" << (c*e-b*f)/D << “ Nghiem y=" << (a*f-c*d)/D <<'\n'; } void main() { HPTB1 p; // định nghĩa 1 hệ phương trình bậc nhất p clrscr(); p.Nhap(); // Truyền thông báo nhập cho p p.XuatNghiem(); // Truyền thông báo xuất nghiệm cho p getch(); }
Thí dụ: Viết chương trình nhập 1 mảng số nguyên int, xuất trị lớn nhất, xuất mảng tăng dần. #include <iostream.h> #include <conio.h> class MangInt { private: int* a, n; public: void Input(); int GetMax(); void AscSort(); void Output(); }; void MangInt:: Input() { do { cout<< “ Number of element:”; cin>> n; } while (n<=0); a= new int[n]; // cấp bộ nhớ for (int i=0; i<n;i++) { cout << “a[“ << i << “]=“; cin>>a[i]; } } Phải hiện thực bên ngoài lớp vì có dùng phát biểu lặp Phân tích Khái niệm liên quan : mảng số int , mô tả bằng int* a, n Tác vụ: Input (nhập), GetMax (lấy trị lớn nhất), AscSort (sắp xếp tăng), Output (xuất). Tất cả đều cần cho bên ngoài truy xuất vì hàm main cần sử dụng các tác vụ này. Giải bài toán: Cần 1 mảng (tên m). Trật tự truyền thông báo: m.Input(); cout << m.GetMax(); m.AscSort(); m.Output;
Viết chương trình nhập 1 mảng số nguyên int, xuất trị lớn nhất, xuất mảng tăng dần. int MangInt:: getMax() { int t=a[0]; for (int i=1; i<n;i++) if (t < a[i]) t=a[i]; return t; } void MangInt:: AscSort() { for (int i=0; i<n-1;++i) for (int j= n-1; j>i ; --j ) if (a[j] < a[j-1]) { int t=a[j]; a[j]=a[j-1]; a[j-1]=t; } } void MangInt::Output() { for (int i=0; i<n;i++) cout << a[i] << ‘ ‘ ; } // Sử dụng lớp void main() { MangInt m; m.Input(); cout <<“ Max val:” << m.GetMax() <<‘\n’; m.AscSort(); cout << “Sorted array\n”; m.Output(); getch(); }
Tóm tắt • Lập trình OOP cũng tương tự như lập trình POP nhưng mô tả bài toán dưới dạng các class, các tác vụ xử lý dữ liệu thành các hành vi của class. • Khai báo class cũng tương tự như khai báo struct nhưng có khác struct ở chỗ đưa các tác vụ thao tác lên struct vào trong class và gọi chúng là các methods của lớp. struct StructName { <data> }; class ClassName { <data> Modifier : Type1 Func1 () { <code>} Modifier : Type2 Func2 () { <code>} }; Chỉ có method public là toàn cục public private protected Type1 Func1 (StructName stru) { <code>} Type2 Func2 (StructName stru) {<code>} các hàm đều toàn cục
Tóm tắt (tt) • Thiết kế class Làm việc với cái gì Tên class. Mô tả nó bằng gì ? Properties Thao tác gì lên nó Methods • Sử dụng lớp là định nghĩa biến (đơn, mảng, pointer) thuộc lớp theo cú pháp định nghĩa biến của C. • Nhập dữ liệu cơ bản: cin >> SimpleVar; • Xuất dữ liệu cơ bản : cou << SimpleData;
Câu 1 Khi hiện thực 1 method cho 1 class nhưng đặt ở bên ngoài khai báo class , trong code của method _____ phép truy cập 1 thành phần protected của chính lớp đó. a- Cho b- Không cho a
Câu 2 Khi hiện thực 1 method cho 1 class nhưng đặt ở bên ngoài khai báo class , trong code của method _____ phép truy cập 1 thành phần priavte của chính lớp đó. a- Cho b- Không cho a
Câu 3 Trong 3 modifier (từ định tính) cho 1 thành phần của class, modifier _____ cho phép bên ngoài truy cập tự do 1 thành phần (chọn 1). a- public b- private c- protected a
b c Câu 4 Trong 3 modifier (từ định tính) cho 1 thành phần của class, hai modifier giới hạn quyền truy cập từ bên ngoài đối với đối tượng thuộc lớp. a- public b- private c- protected
Câu 5 cin >> S ; // S là biến chuỗi ký tự Chọn phát biểu sai. a- S có thể có khoảng trống. b- S không chứa khoảng trống. a
Câu 6 cin >> x1>> x2; cout << x2 << x1; Chọn phát biểu đúng. a- x1 được nhập trước rồi xuất trước b- x2 được nhập trước rồi xuất trước c- x1 được nhập trước rồi xuất sau d- x2 được nhập trước rồi xuất sau c