Lập trình C#

Kiểu class trong lập trình C#

Kiểu class trong lập trình C#
Được viết bởi Minh Hoàng

Series lập trình C#, ngôn ngữ lập trình hiện đại và mạnh mẽ.

Như chúng ta đã biết, C# là ngôn ngữ lập trình hướng đối tượng, chính vì thế việc tạo ra các đối tượng (objects) trong một chương trình viết bằng C# là điều không thể thiếu. Vậy làm thế nào để tạo ra các đối tượng (objects) mong muốn khi cần sử dụng chúng trong chương trình của mình? Khi đó chúng ta cần xây dựng class trong chương trình là có thể tạo ra đối tượng. Chi tiết các bạn cùng theo dõi những nội dung bên dưới:

  1. Class là gì? Gồm những thành phần nào?
  2. Cách tạo đối tượng và truy xuất các thành phần của lớp
  3. Hàm dựng/Hàm khởi tạo Constructor
  4. Hàm hủy Destructor
1. Class là gì? Gồm những thành phần nào?
1. Class là gì? Gồm những thành phần nào?

– Một lớp/class là một khái niệm mô tả cho những thực thể/đối tượng có chung tính chất/thuộc tính và hành vi/phương thức. Lớp định nghĩa những thuộc tính và hành vi được dùng cho những đối tượng của lớp đó. Do đó có thể nói lớp là một khuôn mẫu cho các đối tượng.

Vậy đối tượng là gì?
Đối tượng là một đại diện, hay có thể nói là một sản phẩm của một class. Tất cả các đối tượng đều có chung những thuộc tính và hành vi mà class định nghĩa. Cách tạo đối tượng giống như cách tạo một biến có kiểu dữ liệu là class.

– Để dễ hình dung, chúng ta có minh họa sau:

Từ class Xe hơi, sẽ tạo ra được nhiều đối tượng có cùng bản chất là xe Mercedes, xe Bmw, xe Audi

Từ class Xe hơi, sẽ tạo ra được nhiều đối tượng có cùng bản chất là xe Mercedes, xe Bmw, xe Audi

Từ class Trái cây, sẽ tạo ra được nhiều đối tượng có cùng bản chất là Banana, Apple, Pineapple, Strawberry

Từ class Trái cây, sẽ tạo ra được nhiều đối tượng có cùng bản chất là Banana, Apple, Pineapple, Strawberry


Class là kiểu dữ liệu do người dùng tự định nghĩa và class là kiểu tham chiếu. Access modifier mặc định cho kiểu class nếu không chỉ định là internal, còn của thuộc tính là private.

– Một class thì bao gồm thuộc tính (là các danh từ) và phương thức (là các động từ). Được khai báo bắt đầu bằng từ khóa class như sau:

<access modifier> class  tên_lớp
{
   // Khai báo các thuộc tính
   <access modifier> <kiểu_dữ_liệu> tên_biến_1;
   <access modifier> <kiểu_dữ_liệu> tên_biến_2;
   ...
   <access modifier> <kiểu_dữ_liệu> tên_biến_n;
   
   // Khai báo các phương thức
   <access modifier> <kiểu_trả_về> tên_phương_thức_1(danh_sách_tham_số)
   {
      // định nghĩa phương thức
   }
   <access modifier> <kiểu_trả_về> tên_phương_thức_2(danh_sách_tham_số)
   {
      // định nghĩa phương thức
   }
   ...
   <access modifier> <kiểu_trả_về> tên_phương_thức_n(danh_sách_tham_số)
   {
      // định nghĩa phương thức
   }
}

Trong đó:

  • access modifier : chỉ định phạm vi truy cập, có thể là public, protected, internal, private.
  • class : từ khóa dùng để khai báo một lớp.
  • tên_lớp, tên_biến, tên_phương_thức : tuân thủ theo quy tắc đặt tên trong lập trình.
  • kiểu_trả_về : có thể là kiểu dữ liệu có sẵn của .Net, hoặc là kiểu dữ liệu do người dùng tự định nghĩa.

– Ví dụ: chúng ta khai báo một class Xe Hơi như bên dưới:

public class XeHoi
{
	// Khai báo các thuộc tính
	public string TenXe;

	public string MauSac;

	public int NamSanXuat;

	// Khai báo các phương thức
	//・Phương thức có kiểu trả về
	public bool Chay()
	{
		Console.WriteLine( "Chạy..." );

		return true;
	}

	//・Phương thức không có kiểu trả về
	public void TangToc(int VanToc)
	{
		Console.WriteLine( "Tăng tốc... {0} km/h", VanToc );
	}
}
2. Cách tạo đối tượng và truy xuất các thành phần của lớp
2. Cách tạo đối tượng và truy xuất các thành phần của lớp
#1. Khởi tạo đối tượng

– Bạn sử dụng toán tử new với cú pháp như sau:

<TênLớp> <tên_đối_tượng> = new TênLớp()

– Ví dụ:

// Khởi tạo đối tượng [toyota] từ lớp [XeHoi]
XeHoi toyota = new XeHoi();

#2. Truy xuất các thành phần của lớp

– Bạn sử dụng toán tử dấu chấm(.) với cú pháp như sau:

// Truy cập thuộc tính
<tên_đối_tượng>.<tên_thuộc_tính>;

// Truy cập phương thức
<tên_đối_tượng>.<tên_phương_thức>( <danh_sách_tham_số_nếu_có> );

– Ví dụ:

// Truy xuất và gán giá trị cho thuộc tính
toyota.TenXe = "Toyota";

// Truy xuất (gọi) phương thức
toyota.TangToc( 80 );


– Ở đây mình chỉ tập trung minh họa cách khai báo đối tượng và sử dụng đối tượng để truy xuất các thành phần của lớp như thế nào. Chúng ta xét ví dụ đơn giản: tạo đối tượng xe toyota từ lớp Xe Hơi, sau đó truy xuất vào thuộc tính Tên xe và phương thức Tăng tốc của lớp Xe hơi:

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			// Khởi tạo đối tượng [toyota] từ lớp [XeHoi]
			XeHoi toyota = new XeHoi();

			// Truy xuất và gán giá trị cho thuộc tính
			toyota.TenXe = "Toyota";

			Console.WriteLine( "Tên xe: " + toyota.TenXe );

			// Truy xuất (gọi) phương thức
			toyota.TangToc( 80 );

			Console.ReadKey();
		}
	}

	public class XeHoi
	{
		// Khai báo các thuộc tính
		public string TenXe;

		public string MauSac;

		public int NamSanXuat;

		// Khai báo các phương thức
		//・Phương thức có kiểu trả về
		public bool Chay()
		{
			Console.WriteLine( "Chạy..." );

			return true;
		}

		//・Phương thức không có kiểu trả về
		public void TangToc(int VanToc)
		{
			Console.WriteLine("Tăng tốc... {0} km/h", VanToc);
		}
	}
}
Kết quả chương trình

Kết quả chương trình

3. Hàm dựng/Hàm khởi tạo Constructor
3. Hàm dựng/Hàm khởi tạo Constructor

– Phương thức khởi tạo constructor là một phương thức đặc biệt và là phương thức đầu tiên được gọi và chỉ gọi một lần khi khởi tạo đối tượng, nó nhằm thiết lập các tham số đầu tiên cho đối tượng.
Nếu class không khai báo constructor, trình biên dịch tự động tạo một constructor mặc định không tham số. Khi đó các biến thành viên sẽ được khởi tạo theo các giá trị mặc định ( kiểu int là 0, bool là false, kiểu tham chiếu là null,… ).

Constructor có một số đặc điểm như sau:

  • Có tên trùng với tên lớp.
  • Không có kiểu trả về.
  • Được tự động gọi khi một đối tượng thuộc lớp được khởi tạo.
  • Có thể có một hoặc nhiều constructor bên trong một lớp.
  • Nếu lớp không khai báo bất kỳ phương thức khởi tạo nào thì trình biên dịch tự động tạo một hàm dựng mặc định không tham số và không có nội dung gì.

– Có 2 loại constructor:

  1. Constructor không tham số: là phương thức khởi tạo mặc định, nếu lập trình viên không khai báo thì trình biên dịch sẽ tự tạo ngầm định. Phương thức này không có tham số. Thường dùng để khởi tạo các giá trị mặc định cho các thuộc tính bên trong class khi khởi tạo đối tượng.
  2. Constructor có tham số: là phương thức khởi tạo có tham số truyền vào. Và khi khởi tạo đối tượng sử dụng bằng phương thức này, chúng ta cần truyền đầy đủ các tham số. Thường dùng để khởi tạo các giá trị cho các thuộc thuộc tính bên trong class khi khởi tạo đối tượng (các giá trị này do người khởi tạo đối tượng truyền vào).

– Cú pháp khai báo constructor:

// Khai báo constructor không tham số
<access modifier> tên_lớp
{
   // định nghĩa phương thức
}

// Khai báo constructor có tham số
<access modifier> tên_lớp(danh_sách_tham_số)
{
   // định nghĩa phương thức
}


– Minh họa cách sử dụng phương thức khởi tạo constructor:

■ Class XeHoi

public class XeHoi
{
	// Khai báo các thuộc tính
	public string TenXe;

	public int NamSanXuat;

	// Constructor không tham số
	public XeHoi()
	{
		// Khởi tạo giá trị cho thuộc tính có thể có hoặc không
		// TenXe = "Toyota";
		// NamSanXuat = 2017;
	}

	// Constructor có tham số
	public XeHoi(string inTenXe, int inNamSanXuat)
	{
		TenXe = inTenXe;
		NamSanXuat = inNamSanXuat;
	}
}


■ Hàm main() khởi tạo đối tượng bằng constructor không tham số

class MinhHoangBlog
{
	static void Main(string[] args)
	{
		// Tạo đối tượng bằng constructor không tham số
		XeHoi car = new XeHoi();

		// Xem giá trị của thuộc tính
		string TenXe = car.TenXe;			// TenXe = null

		int NamSanXuat = car.NamSanXuat;    // NamSanXuat = 0

		Console.ReadKey();
	}
}


Như các bạn thấy, nếu chúng ta tạo đối tượng bằng constructor không tham số mà không khởi tạo giá trị mặc định cho các biến thành viên(TenXe, NamSanXuat), thì các biến này sẽ được khởi tạo bằng giá trị mặc định của kiểu dữ liệu: string là null, int là 0.

■ Hàm main() khởi tạo đối tượng bằng constructor có tham số

class MinhHoangBlog
{
	static void Main(string[] args)
	{
		// Tạo đối tượng bằng constructor không tham số
		XeHoi car = new XeHoi("Audi", 2010);

		// Xem giá trị của thuộc tính
		string TenXe = car.TenXe;           // tenXe = Audi

		int NamSanXuat = car.NamSanXuat;    // namSanXuat = 2010

		Console.ReadKey();
	}
}


Còn khi chúng ta tạo đối tượng bằng constructor có tham số thì giá trị của các biến thành viên sẽ chính là các giá trị được truyền vào tương ứng cho constructor.

Một số điểm lưu ý:

  • Trường hợp trong một lớp có nhiều constructor thì tùy vào cách bạn gọi constructor là có tham số hay không tham số, và số lượng tham số truyền vào mà chỉ có một constructor tương ứng được gọi để tạo đối tượng.
  • Các tham số của constructor có tham số sẽ mang các giá trị tương ứng cho các thuộc tính bên trong lớp vì thế nên:
    • Khai báo chúng có cùng kiểu dữ liệu với thuộc tính tương ứng.
    • Đặt tên chúng gợi nhớ đến thuộc tính tương ứng để tránh nhầm lẫn. Và khi muốn truy xuất vào thuộc tính nào thì cũng dễ hiểu, dễ nhận biết khi đọc code.
4. Hàm hủy Destructor
4. Hàm hủy Destructor

– Phương thức huỷ bỏ destructor là phương thức đặc biệt được gọi đến trước khi một đối tượng bị thu hồi. Rất hữu ích để giải phóng tài nguyên bộ nhớ trước khi kết thúc chương trình.

Destructor có một số đặc điểm như sau:

  • Có tên trùng với tên lớp.
  • Không có kiểu trả về.
  • Không có tham số.
  • Không được chỉ định phạm vi truy cập.
  • Không được kế thừa(inherited) hoặc nạp chồng(overloaded).
  • Mỗi lớp chỉ có duy nhất một phương thức destructor.
  • Destructor không thể được gọi từ đối tượng, mà nó sẽ được gọi ngầm một cách tự động.
  • Destructor chỉ có trong kiểu class, mà không có trong kiểu struct.

– Cú pháp khai báo:

~TênLớp()
{
	// cleanup statements
}

– Ví dụ:

// Khai báo destructor
~XeHoi()
{
	// cleanup statements
}


Lưu ý:

  • Nếu destructor là rỗng(empty – không có nội dung) thì không nên sử dụng. Vì khi một class có chứa phương thức destructor thì khi đó một entry sẽ được tạo trong queue(hàng đợi) của Finalize.
  • Khi destructor được gọi thì Garbage Collector(GC) được gọi để xử lý. Do đó mà gây ra một tổn thất không cần thiết về hiệu suất của chương trình.
  • Vì vậy nếu không có xử lý gì đặc biệt để giải phóng vùng nhớ thì không khai báo phương thức destructor.
Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi! Minh Hoàng Blog | Nào cùng vui hehe


Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp người đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[…]

Bình luận của bạn

Be the First to Comment!

avatar
wpDiscuz
Chúc bạn có một cuộc sống ngoại hạng!