Hàm Khởi Tạo Và Hàm Huỷ

This entry is part 3 of 10 in the series This entry is part 3 of 10 in the series Hướng đối tượng người tiêu dùng C + +

Chào cả nhà
Trong bài viết này chúng ta sẽ đi tìm hiểu một hàm thành viên rất quan trọng của lớp đó chính là hàm khởi tạo và hàm huỷ.

Hàm khởi tạo (Constructor)

Hàm khởi tạo là gì?

Hàm khởi tạo là một hàm thành viên đặc biệt quan trọng của một lớp. Nó sẽ được tự động hóa gọi đến khi một đối tượng người tiêu dùng của lớp đó được khởi tạo .

Sự khác biệt giữa hàm tạo và hàm thành viên thông thường

Một hàm tạo sẽ khác những hàm thông thường ở những điểm sau:

Bạn đang đọc: Hàm Khởi Tạo Và Hàm Huỷ

  • Có tên trùng với tên lớp
  • Không có kiểu dữ liệu trả về ( kể cả kiểu void)
  • Tự động được gọi khi một đối tượng thuộc lớp được tạo ra
  • Nếu chúng ta không khai báo một hàm tạo, trình biên dịch C++ sẽ tự động tạo một hàm tạo mặc định cho chúng ta (sẽ là hàm ​​không có tham số nào và có phần thân trống).

Hàm tạo hoàn toàn có thể rất có ích để thiết lập những giá trị khởi tạo cho những biến thành viên đơn cử .
Ví dụ đơn thuần về hàm khởi tạo :

012345678910

classsinhvien

{

private:

stringten;

inttuoi;

public:

sinhvien();/ / Đây là hàm khởi tạo

~sinhvien();

};

Các loại hàm khởi tạo

Hàm khởi tạo về cơ bản sẽ được chia làm 3 loại :

  1. Hàm khởi tạo không tham số (Cũng có thể gọi là hàm tạo mặc định – Default Constructor )
  2. Hàm khởi tạo có tham số ( Parameterized Constructor )
  3. Hàm khởi tạo sao chép ( Copy Constructor )

Hàm Khởi Tạo

Hàm khởi tạo không tham số ( Default Constructor )

Hàm tạo loại này sẽ không truyền vào bất kỳ một đối số nào

01234567891011121314

classsinhvien

{

private:

stringten;

inttuoi;

public:

sinhvien()

{

this->ten=” “;

this->tuoi=0;

}

~sinhvien();

};

Như trong ví dụ trên, hàm tạo sinhvien ( ) không hề có đối số nào được truyền vào .
Theo quan điểm riêng của mình thì thường thì trong hàm loại này mình sẽ gán cho tổng thể những thuộc tính về giá trị mặc định .
Trong ví dụ trên :

  • Thuộc tính ten thuộc kiểu string mình sẽ đưa về mặc định là một chuối rỗng "".
  • Thuộc tính tuoi thuộc kiểu int mình sẽ đưa về mặc định là 0.

Hàm khởi tạo có tham số ( Parameterized Constructor )

Với loại hàm tạo này ta hoàn toàn có thể truyền đối số cho chúng. Thông thường, những đối số này giúp khởi tạo một đối tượng người tiêu dùng khi nó được tạo .
Để khai báo một hàm khởi tạo có tham số chỉ cần thêm những tham số vào nó giống như cách bạn thêm tham số bất kể hàm nào khác. Khi bạn xác lập phần thân của hàm tạo, hãy sử dụng những tham số để khởi tạo đối tượng người tiêu dùng .

01234567891011121314

classsinhvien

{

private:

stringten;

inttuoi;

public:

sinhvien(stringparam_ten,intparam_tuoi)

{

this->ten=param_ten;

this->tuoi=param_tuoi;

}

~sinhvien();

};

Sau khi khai báo hàm trong lớp, ta hoàn toàn có thể thuận tiện dùng nó bằng cách truyền tham số trong khi khởi tạo đối tượng người tiêu dùng .

0123456

intmain()

{

sinhvienobj(” lap Trinh Khong Kho “,5);/ / Ta truyền luôn tham số trong khi khới tạo đối tượng người dùng

}

Lưu ý:

  • Khi một đối tượng được khai báo trong hàm khởi tạo có tham số, các giá trị ban đầu phải được truyền dưới dạng đối số cho hàm tạo.
  • Cách khai báo đối tượng bình thường có thể sẽ gây lỗi.
    Điều này có nghĩa là bình thường để khai báo một đối tượng bạn sẽ khai báo bằng cú pháp:
012

sinhvienobj;

Nhưng do hàm khởi tạo là hàm có tham số nên cú pháp sẽ phải là :

012

sinhvienobj(” Lap Trinh Khong Kho “,5);

  • Các hàm khởi tạo có thể được gọi một cách rõ ràng hoặc ngầm định.
    0123

    sinhvienobj=sinhvien(” Lap Trinh Khong Kho “,5);/ / Đây là cách rõ ràng

    sinhvienobj(” Lap Trinh Khong Kho “,5);/ / Đây là cách ngầm định

    Nhưng thông thường để tiết kiệm code thì chúng ta hay sử dụng các ngầm định hơn.

Công dụng của hàm khởi tạo có tham số
  • Nó được sử dụng để khởi tạo các thành phần dữ liệu khác nhau của các đối tượng khác nhau với các giá trị khác nhau khi chúng được tạo.
  • Nó được sử dụng để nạp chồng các hàm khởi tạo.
    Nạp chồng? Có thể hiểu đơn giản là ta sẽ có nhiều hơn một hàm khởi tạo trong cùng một lớp. Và phần này thì sẽ được mình trình bài trong bài sau nhé.

Hàm khởi tạo sao chép ( Copy Constructor )

Hàm khởi tạo sao chép là gì?

Hàm khởi tạo sao chép là một hàm tạo mà tạo một đối tượng bằng việc khởi tạo nó với một đối tượng của cùng lớp đó, mà đã được tạo trước đó.

Một hàm khởi tạo sao chép sẽ có nguyên mẫu chung như sau :

012345

ClassName(constClassNamevà old_obj)

{

/ / Code

}

Trong đó Classname là tên của lớp, old_obj là đối tượng cũ sẽ lấy làm gốc để sao chép sang đối tượng mới

Ví dụ đơn thuần về hàm khởi tạo sao chép :

01234567891011121314151617

18

1920212223242526272829303132333435363738

/ * Code by KingNNT * /

#include

usingnamespacestd;

classPoint

{

private:

intx,y;

public:

Point(intx1,inty1)

{

x=x1;

y=y1;

}

/ / Hàm khởi tạo sao chép

Point(constPointvà p2 )

{

x = p2. x ;

y=p2.y;

}

intgetX(){returnx;}

intgetY(){returny;}

};

intmain()

{

Pointp1(10,15);/ / Hàm khởi tạo có tham số thường thì

Pointp2=p1;/ / hàm khởi tạo sao chép được gọi ở đây

cout<<" p1. x = "<cout<<" p2. x = "<return0;

}

Sau khi chạy chương trình ta sẽ có tác dụng :

0123 p1. x = 10, p1. y = 15p2. x = 10, p2. y = 15
Một hàm khởi tạo sao chép sẽ được gọi khi nào?

Hàm khởi tạo sao chép sẽ được gọi khi :

  1. Khi một đối tượng của lớp được trả về bằng một giá trị.
  2. Khi một đối tượng của lớp được truyền đối số dưới dạng tham số của một hàm.
  3. Khi một đối tượng được tạo ra dựa trên một đối tượng khác cùng lớp.
  4. Khi trình biên dịch tạo một đối tượng tạm thời.

Tuy nhiên trên thực tiễn thì không chắc như đinh rằng hàm khởi tạo sao chép sẽ được gọi trong toàn bộ 4 trường hợp ở phía trên. Vì C + + tiêu chuẩn sẽ được cho phép trình biên dịch tối ưu hoá bản sao trong một số ít trường hợp nhất định .
Một ví dụ cho điều này là : Ví dụ về tối ưu hoá giá trị trả về ( Có thể gọi tắt là RVO ). Xem tại đây

Lưu ý:

Nếu một hàm tạo sao chép không được định nghĩa trong một lớp, trình biên dịch sẽ tự nó định nghĩa nó. Vì thế phải thật chú ý quan tâm nếu lớp có những biến con trỏ hoặc có sử dụng cấp phép bộ nhớ động thì nên viết lại hàm .
Chia sẻ nhỏ một chút ít là mình đã từng mắc lỗi tại đây do khi sử dụng cấp phép bộ nhớ động mà không viết lại hàm khởi tạo sao chép do đó dẫn đến việc truy vấn sai ô nhớ .

Hàm huỷ (Deconstructor)

Hàm huỷ là gì?

Hàm huỷ cũng là một hàm thành viên đặc biệt quan trọng giống như hàm tạo, nó được dùng để phá huỷ hoặc xoá một đối tượng người tiêu dùng trong lớp .

Hàm huỷ sẽ được gọi khi nào?

Hàm hủy được gọi tự động hóa khi một đối tượng người dùng thoát khỏi khoanh vùng phạm vi của nó ( Scope ) :

  1. Một chức năng kết thúc.
  2. Chương trình kết thúc.
  3. Một khối chứa các biến cục bộ kết thúc.
  4. Một toán tử delete được gọi

Hàm huỷ khác những hàm thành viên bình thường ở đâu?

  • Cũng giống với hàm tạo, hàm huỷ có tên trùng với tên của lớp, nhưng điểm khác biệt ở đây là sẽ có thêm ~ ở đầu.
  • Hàm huỷ là một hàm không có đối số truyền vào, và cũng không trả về giá trị ( kể cả void)
0123456789101112131415161718

classsinhvien

{

private:

stringten;

inttuoi;

public:

sinhvien()

{

this->ten=” “;

this->tuoi=0;

}

~sinhvien()/ / Đây là hảm huỷ

{

this->ten=” “;

this->tuoi=0;

}

}

Có thể có nhiều hơn một hàm huỷ ở trong cùng một lớp không?

Câu trả lời ở đây là không nhé.
Khác với hảm khởi tạo, hàm huỷ có thể có một và chỉ một mà thôi.

Khi nào thì ta cần tự định nghĩa một hàm huỷ?

Với C++ thì nếu ta không khai báo một hàm huỷ, trình biên dịch cũng sẽ tự định nghĩa một hàm huỷ. Thông thường thì hàm huỷ này hoạt động khá tốt, nhưng khi bài toán có sử dụng con trỏ, hoặc cấp phát bộ nhớ động thì ban nên khai báo một hàm huỷ riêng để tránh rỏ rỉ bộ nhớ.

Nhưng với bản thân mình thường thì mình vẫn sẽ khai báo một hàm huỷ mặc dầu có dùng con trỏ hay cấp phát động hay không, và trong hàm huỷ đó mình sẽ đưa những thuộc tính của lớp về giá trị mặc định ( giống với hàm khởi tạo không tham số ) .

Một hàm huỷ có thể là một hàm ảo hay không ?

Tất nhiên là có rồi. Và bạn hoàn toàn có thể xem cụ thể : Tại đây
Bài viết của mình xin được kết thúc tại đây. Mọi thể comment ở bên dưới nếu thấy bất kể điều gì không đúng chuẩn, hoặc đơn thuần là muốn san sẻ thêm những kiến thức và kỹ năng tới mọi người. Cảm ơn mọi người. Chào tạm biệt và hẹn gặp lại !

Tài liệu tham khảo