Bài giảng Kỹ thuật lập trình - Chương 6: Lớp và đối tượng I

6.1 Tạo và hủy ₫ối tượng
Có bao nhiêu cách ₫ể tạo/hủy ₫ối tượng?
ƒ Tạo/hủy tự ₫ộng: Định nghĩa một biến thuộc một lớp
— Bộ nhớ của ₫ối tượng (chứa các dữ liệu biến thành viên) ₫ược tự
₫ộng cấp phát giống như với một biến thông thương
— Bộ nhớ của ₫ối tượng ₫ược giải phóng khi ra khỏi phạm vi ₫ịnh
nghĩa
class X {
int a, b;
...
};
void f( X x1) {
if (..) {
X x2;
...
}
}
X x;
Đối tượng ₫ược tạo ra trong ngăn xếp
Đối tượng ₫ược tạo ra trong vùng dữ liệu chương trình 
pdf 27 trang thiennv 08/11/2022 3500
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 6: Lớp và đối tượng I", để tải tài liệu gốc về máy hãy click vào nút Download ở trên.

File đính kèm:

  • pdfbai_giang_ky_thuat_lap_trinh_chuong_6_lop_va_doi_tuong_i.pdf

Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 6: Lớp và đối tượng I

  1. Phiên bảnthứ nhất class Vector { int nelem; double* data; public: Vector() : nelem(0), data(0) {} Vector(int n, double d =0.0); Các hàm thành viên Vector(int n, double *array); const không cho phép Vector(const Vector&); thay ₫ổibiến thành ~Vector(); viên của ₫ốitượng! int size() const { return nelem; } double getElem(int i) const { return data[i];} void putElem(int i, double d) { data[i] = d; } private: void create(int n) { data = new double[nelem=n]; } void destroy() { if (data != 0) delete [] data; } }; Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 11
  2. Hàm tạo: cấp phát tài nguyên và khởitạo Hàm hủy: dọndẹp, giải phóng tài nguyên Vector::Vector(int n, double d) { create(n); while (n > 0) data[n] = d; } Vector::Vector(int n, double* p) { create(n); while (n > 0) data[n] = p[n]; } Vector::~Vector() { destroy(); } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 12
  3. Trường hợp ₫ặcbiệt: Hàm tạobảnsao ƒ Hàm tạobảnsao₫ượcgọi khi sao chép ₫ốitượng: — Khi khai báo các biến x2-x4 như sau: X x1; X x2(x1); X x3 = x1; X x4 = X(x1); — Khi truyềnthamsố qua giá trị cho mộthàm, hoặckhimộthàmtrả về một ₫ốitượng void f(X x) { } X g( ) { X x1; f(x1); return x1; } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 13
  4. Cú pháp chuẩnchohàm tạobảnsao? class X { int a, b; public: (1) Truyềnthamsố qua giá trị X() : a(0), b(0) {} yêu cầu sao chép x1 sang x!!! X(X x); // (1) (2) Như (1) X(const X x); // (2) ? X(X& x); // (3) (3) Không sao chép tham số, X(const X& x); // (4) nhưng x có thể bị vô tình thay ₫ổitronghàm }; (4) Không sao chép tham số, an void main() { toàn cho bản chính => cú pháp X x1; chuẩn! X x2(x1); } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 14
  5. Khi nào cần ₫ịnh nghĩahàmtạobảnsao? ƒ Khi nào hàm tạobảnsaomặc ₫ịnh không ₫áp ứng ₫ượcyêucầu. ƒ Ví dụ, nếuhàmtạobảnsaokhông₫ược ₫ịnh nghĩa, mã do compiler tự₫ộng tạoracholớpVector sẽ có dạng: Vector::Vector(const Vector& b) : nelem(b.nelem), data(b.data) {} ƒ Vấn ₫ề: Sao chép con trỏ thuần túy, hai ₫ốitượng cùng sử dụng chung bộ nhớ phầntử Vector a(5); a.nelem : 5 b.nelem : 5 Vector b(a); a.data b.data 0 0 0 0 0 ƒ Trường hợpnày, phải ₫ịnh nghĩalạinhư sau: Vector::Vector(const Vector& a) { create(a.nelem); for (int i=0; i < nelem; ++i) data[i] = a.data[i]; } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 15
  6. Mộtsố₫iểmcầnlưuý ƒ Nhiềuhàmtạonhưng chỉ có mộthàmhủy=> hàmhủyphải nhấtquánvớitấtcả hàm tạo —Trongvídụ lớp Vector, có hàm tạocấpphátbộ nhớ, nhưng hàm tạo mặc ₫ịnh thì không => hàm hủycầnphânbiệtrõcáctrường hợp ƒ Khi nào hàm tạocócấp phát chiếmdụng tài nguyên thì cũng cần ₫ịnh nghĩalạihàmhủy ƒ Trong mộtlớpmàcó₫ịnh nghĩahàmhủythìgầnnhư chắcchắn cũng phải ₫ịnh nghĩahàmtạobảnsao(nếunhư cho phép sao chép) ƒ Mộtlớpcóthể cấmsaochépbằng cách khai báo hàm tạobản sao trong phần private, ví dụ: class Y { int a, b; Y(const&); }; void main() { Y y1; Y y2=y1; // error! } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 16
  7. 6.3 Nạpchồng toán tử ƒ Mộttrongnhững kỹ thuậtlập trình hay nhấtcủaC++ ƒ Chophépápdụng các phép toán vớisố phứchoặcvớivector sử dụng toán tử +, -, *, / tương tự như vớicácsố thực. Ví dụ: class Complex { double re, im; public: Complex(double r = 0, double i =0): re(r),im(i) {} }; Complex z1(1,1), z2(2,2); Complex z = z1 + z2; // ??? ƒ Bảnchấtcủavấn ₫ề? Dòng mã cuối cùng thựcracóthể viết: Complex z = z1.operator+(z2); Hàm toán tử có thể thực hoặc hiện là hàm thành viên Complex z = operator+(z1,z2); hoặc hàm phi thành viên Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 17
  8. Ví dụ: bổ sung các phép toán số phức class Complex { double re, im; public: Complex(double r = 0, double i =0): re(r),im(i) {} double real() const { return re; } double imag() const { return im; } Complex operator+(const Complex& b) const { Complex z(re+b.re, im+b.im); return z; } Complex operator-(const Complex& b) const { return Complex(re-b.re,im-b.im); } Complex operator*(const Complex&) const; Complex operator/(const Complex&) const; Complex& operator +=(const Complex&); Complex& operator -=(const Complex&); }; Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 18
  9. #include “mycomplex.h” Complex Complex::operator*(const Complex& b) const { // left for exercise! } Complex Complex::operator/(const Complex& b) const { // left for exercise! } Complex& Complex::operator +=(const Complex& b) { re += b.re; im += b.im; return *this; } Complex& operator -=(const Complex&) { } bool operator==(const Complex& a, const Complex& b) { return a.real() == b.real() && a.imag() == b.imag(); } void main() { Complex a(1,1), b(1,2); Complex c = a+b; a = c += b; // a.operator=(c.operator+=(b)); if (c == a) { } } return ? Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 19
  10. Các toán tử nàocóthể nạpchồng? ƒ Hầuhết các toán tử có trong C++, ví dụ — Các toán tử số học: ++ + - * / % += -= — Các toán tử logic, logic bit: && || ! & &= | |= — Các toán tử so sánh: == != > = > >>= * , ƒ Chỉ có 4 toán tử không nạpchồng ₫ược: —Toántử truy nhậpphạmvi (dấuhaichấm ₫úp) :: —Toántử truy nhập thành viên cấutrúc(dấuchấm) . —Toántử gọihàmthànhviênqua con trỏ *-> —Toántử₫iềukiện ? : Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 20
  11. Mộtsố qui ₫ịnh ƒ Có thể thay ₫ổingữ nghĩacủamộttoántử cho các kiểumới, nhưng không thay ₫ổi ₫ượccúpháp(vídụ số ngôi, trình tựưu tiên thựchiện, ) ƒ Trong mộtphéptoán₫ịnh nghĩalại, phảicóítnhấtmộttoán hạng có kiểumới (struct, union hoặc class) => không ₫ịnh nghĩa lạichocáckiểudữ liệucơ bảnvàkiểudẫnxuấttrựctiếp ₫ược! —Vídụ không thể₫ịnh nghĩalạitoántử ^ là phép tính lũythừacho các kiểusố họccơ bản (int, float, double, ) ƒ Chỉ nạpchồng ₫ược các toán tử có sẵn, không ₫ưathêm₫ược các toán tử mới —Vídụ không thể bổ sung ký hiệutoántử cho phép toán lũythừa ƒ Nạpchồng toán tử thựcchấtlànạpchồng tên hàm => cầnlưuý các qui ₫ịnh về nạpchồng tên hàm ƒ Đasố hàm toán tử có thể nạpchồng hoặc dướidạng hàm thành viên, hoặc dướidạng hàm phi thành viên ƒ Mộtsố toán tử chỉ có thể nạpchồng bằng hàm thành viên ƒ Mộtsố toán tử chỉ nên nạpchồng bằng hàm phi thành viên Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 21
  12. Nạpchồng toán tử [] ƒ Yêu cầu: truy nhập các phầntử củamột ₫ốitượng thuộclớp Vector vớitoántử [] giống như₫ốivớimộtmảng Vector v(5,1.0); double d = v[0]; // double d = v.operator[](0); v[1] = d + 2.0; // v.operator[](1) = d + 2.0; const Vector vc(5,1.0); d = vc[1];// d = operator[](1); ƒ Giảipháp class Vector { public: double operator[](int i) const { return data[i]; } double& operator[](int i) { return data[i]; } }; Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 22
  13. Nạpchồng toán tử gán (=) ƒ Giống như hàm tạobảnsao, hàmtoántử gán ₫ược compiler tự ₫ộng bổ sung vào mỗilớp ₫ốitượng => mã hàm thựchiệngán từng bit dữ liệu ƒ Cú pháp chuẩncủahàmtoántử gán cho mộtlớpX tương tự cú pháp các phép tính và gán: X& operator=(const X&); ƒ Khi nào cần ₫ịnh nghĩalạihàmtạobảnsaothìcũng cần(và cũng mớinên) ₫ịnh nghĩalại hàm toán tử gán ƒ Ví dụ, nếuhàmtoántử gán không ₫ược ₫ịnh nghĩa, mã do compiler tự₫ộng tạoracholớpVector sẽ có dạng: Vector& Vector::operator=(const Vector& b) { nelem = b.nelem; data = b.data return *this; } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 23
  14. ƒ Vấn ₫ề tương tự như hàm tạobảnsaomặc ₫ịnh, thậmchícòn tồitệ hơn { Vector a(5), b(3), c; b = a; c = a; } // calling destructor for a, b and c causes // 3 times calling of delete[] operator for the // same memory space a.nelem : 5 b.nelem : 5 c.nelem : 5 a.data b.data c.data 0 0 0 0 0 0 0 0 Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 24
  15. Nạpchồng toán tử gán cho lớpVector Vector& Vector::operator=(const Vector& b) { if (nelem != b.nelem) { destroy(); create(b.nelem); } for (int i=0; i < nelem; ++i) data[i] = b.data[i]; return *this; } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 25
  16. 6.4 Khai báo friend ƒ Vấn ₫ề: Mộtsố hàm phi thành viên thựchiện bên ngoài, hoặc hàm thành viên củamộtlớp khác không truy nhập ₫ượctrực tiếpvàobiếnriêngcủamột ₫ốitượng => thực thi kém hiệuquả ƒ Giải pháp: Cho phép mộtlớp khai báo friend, có thể là mộthàm phi thành viên, một hàm thành viên củamộtlớpkhác, hoặccả mộtlớpkhác ƒ Ví dụ class Complex { friend bool operator==(const Complex&,const Complex&); friend class ComplexVector; friend ComplexVector Matrix::eigenvalues(); } bool operator==(const Complex& a, const Complex& b) { return a.re == b.re && a.im == b.im; } Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 26
  17. Bài tậpvề nhà ƒ Hoàn chỉnh lớpVector vớinhững phép toán cộng, trừ, nhân/chia vớisố vô hướng, nhân vô hướng và so sánh bằng nhau ƒ Dựatrêncấu trúc List và các hàm liên quan ₫ãthựchiệntrong chương 4, hãy xây dựng lớp ₫ốitượng List với các hàm thành viên cầnthiết. Chương 6: Lớpvàđốitượng II © 2007 AC - HUT 27