Có những cách khác nhau để một trình biên dịch nói về dữ liệu, và C# có hai cách. Mọi kiểu dữ liệu
trong C# đều rơi vào một trong hai loại:
Kiểu giá trị (Value type)
Kiểu tham chiếu (Reference type)
Tôi sẽ giải thích các điểm khác nhau của mỗi loại trong những mục sau.
17 trang |
Chia sẻ: lylyngoc | Lượt xem: 1675 | Lượt tải: 2
Bạn đang xem nội dung tài liệu Lập trình C# - Phần 3: Giới thiệu về Lớp, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 1
Lập trình C#
Dịch từ cuốn sách Beginning C Sharp Game Programming
Phần 3: Giới thiệu về Lớp
Gía trị với Tham chiếu
Có những cách khác nhau để một trình biên dịch nói về dữ liệu, và C# có hai cách. Mọi kiểu dữ liệu
trong C# đều rơi vào một trong hai loại:
Kiểu giá trị (Value type)
Kiểu tham chiếu (Reference type)
Tôi sẽ giải thích các điểm khác nhau của mỗi loại trong những mục sau.
Kiểu dữ liệu
Một kiểu giá trị thường là một miếng nhỏ của dữ liệu mà hệ thống dành rất ít thời gian để sắp xếp.
Bạn đã sử dụng kiểu giá trị trong Phần 2 với tất cả các kiểu dữ liệu số được xây dựng sẵn. Mọi thứ
được liệt kê trong bảng 2.1 – như là int, float và vâng vâng – là một kiểu giá trị.
Ghi chú
Kiểu giá trị được tạo trên ngăn xếp hệ thống (system stack). Bạn không cần thiết để biết nó là
gì, nhưng nếu bạn cảm thấy thú vị, tôi khuyên bạn rằng nên tự nghiên cứu nó. Chủ đề này
vượt ra ngoài phạm vi của quyển sách này, vì vậy tôi không đủ chỗ để giải thích nó ở đây,
nhưng nó sẽ giúp bạn hiểu chính xác làm sao máy vi tính hoạt động, nó sẽ ảnh hưởng đến
việc tạo chương trình của bạn nhanh hơn và hiệu quả hơn.
Kiểu giá trị đơn giản và rất minh bạch để sử dụng, như là đoạn mã sau:
int x = 10, y = 20;
x = y; // Giá trị của y được chép vào x
y = 10; // y được gán bằng 10
Bên cạnh những kiểu đượcdựng sẵn, cấu trúc (structure) cũng là một kiểu giá trị, nhưng tôi sẽ đề cập
về sau trong phần này.
Kiểu tham chiếu
Kiểu tham chiếu hoàn toàn khác biệt so với kiểu giá trị. Lớp, khác với cấu trúc, luôn luôn là kiểu tham
chiếu. Kiểu tham chiếu, thay vì lưu dữ liệu một cách trực tiếp, nó lại lưu một địa chỉ, và địa chỉ đó trỏ
tới dữ liệu thật trong nơi nào đó của máy vi tính. Xem hình 3.1.
Khai báo một Kiểu Tham chiếu
Một trong những điểm khác nhau lớn nhất giữa kiểu giá trị và tham chiếu là cách mà bạn khai báo cho
nó. Một kiểu tham chiếu phải được tạo bởi từ khóa new (giả sử như chúng ta có một lớp tên Foo):
Foo x = new Foo();
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 2
Trông có vẻ nhiều việc cần làm, nhưng bạn sẽ quen với nó. Cơ bản, đoạn mã thực hiện hai công việc.
Đó là:
1. Tạo một kiểu tham chiếu mới tên x, và
2. Tạo một đối tượng Foo mới trong đống dữ liệu và trỏ x đến đó.
Hình 3.1 Kiểu giá trị được lưu trực tiếp, trong khi kiểu tham chiếu lưu một địa chỉ trỏ tới dữ liệu thật.
Ghi chú
Đống dữ liệu (Heap) là một phần khác của máy vi tính để lưu trữ dữ liệu. Tôi không có đủ
chỗ để giải thích nó ở đây; đó chỉ là một vài thứ khác bạn nên nghiên cứu cho riêng bạn nên
bạn cảm thấy thú vị.
Đương nhiên, bạn không cần phải thực hiện chúng một lượt. Bạn có thể dễ dàng tách chúng ra như thế
này:
Foo x;
x = new Foo();
Nó tùy thuộc vào bạn.
Chơi đùa với các Tham chiếu
Và bây giờ là lúc để chơi đùa với các tham chiếu, nó là thứ mà bạn chưa gặp trước đây. Không may
cho bạn, các tham chiếu không hoạt động theo cách của các kiểu dữ liệu, mà nó có thể gây bối rối một
chút.
Đây là phần mà các tham chiếu có vẻ hơi khó hiểu một chút. Bạn hoàn toàn phải nhớ điều này mọi lúc
môi nơi khi sử dụng các tham chiếu, còn không chươn trình của bạn sẽ trở thành một mớ hỗn độn. Ví
dụ, hãy thử đoán xem đoạn mã này làm gì:
Foo x = new Foo();
Foo y = new Foo();
y = x;
// Thay đổi y ở đây
Bạn có nghĩ sau khi đọan mã này thực thi, x giữ nguyên trạng thái ban đầu và y thay đổi, đúng
không ? Sai !!! Chúng cùng thay đổi. Hãy nghe tôi – có một chút khó khăn để nhìn nhận nó, nhưng nó
có nghĩa. Sơ đồ có thể giúp, nhìn hình 3.2.
int x
10
Int32 y
địa chỉ của
dữ liệu
10
Kiểu giá trị
Kiểu tham chiếu
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 3
Hình 3.2 Gán x cho y làm y trỏ tới dữ liệu của x, và không thực sự sao chép giá trị như bạn mong đợi.
Cơ bản, dòng này thật sự đã làm rối tung mọi thứ lên:
y = x;
Điều gì thật sự đã hoàn thành? Bạn muốn sao chép giá trị từ x sang y, nhưng điều đó đã không xảy ra.
Thay vào đó, vì chúng là những kiểu tham chiếu, máy vi tính sẽ trỏ y vào cùng dữ liệu mà x trỏ vào.
Vì vậy x và y bây giờ trỏ đến cùng một dữ liệu trong bộ nhớ, và thực hiện thao tác nào trên y sẽ làm
giống vậy đối với x.
Bộ thu gom rác
Trong ví dụ hình 3.2, bạn có thể ghi nhận rằng y đã giành lấy một vùng nhớ, và sau đó nó bị bỏ qua
khi gán x cho y. Vậy điều gì sẽ xảy ra đối với vùng nhớ mà y trỏ tới trước đó?
Trong những ngôn ngữ cũ, như C, vùng nhớ đó sẽ bị mất mãi mãi. Bạn sẽ tạo cái gọi là con trỏ treo
(dangling pointer), là các con trỏ giống các tham chiếu; máy vi tính biết rằng vùng nhớ đã được sử
dụng, nhưng chương trình của bạn sẽ quên nó ở đâu, và bạn sẽ không bao giờ có thể lấy lại vùng nhớ
đó được nữa trừ khi bạn tắt chương trình đi.
C# giải quyết được vấn đề này bởi bộ thu gom rác. Mỗi lần bạn tạo một mảnh dữ liệu trong C#, .NET
runtime sẽ theo dõi chương trình của bạn trỏ đến dữ liệu đó bao nhiêu lần, và nếu số lần đó về 0, thì
bộ thu gom rác sẽ phát hiện và giải phóng vùng nhớ đó để sử dụng cho thứ khác.
Không thể có rò rỉ bộ nhớ trong C#.
null
Có một giá trị đặc biệt mà bạn có thể sử dụng với kiểm tham chiếu; nó gọi là null. Giá trị null có
nghĩa là “chẳng có gì”. Nếu bạn đặt một tham chiếu đến null, thì bạn đang nói với máy vi tính rằng
tham chiếu đó chẳng trỏ tới đâu. Những ngôn ngữ cũ hơn sử dụng giá trị 0 để biểu thị nó, nhưng
null thì dễ đọc hơn.
x
y
Foo x = new Foo();
Foo y = new Foo();
dữ liệu
dữ liệu
x
y
y = x;
dữ liệu
dữ liệu
x
y
// Thay đổi y
dữ liệu thay đổi
dữ liệu
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 4
Cơ bản về Cấu trúc (Structure) và Lớp (Class)
Trong những ngày đầu của ngôn ngữ máy tính, ngôn ngữ lập trình khá đơn giản, và bạn có thể chỉ tạo
được một số lượng biến giới hạn. Điều này rõ ràng làm cho chương trình rất hạn chế và khá tồi tệ. Ví
dụ, bạn sẽ tạo ra chương trình như thế này trong những ngôn ngữ lập trình cũ:
int SpaceshipArmor;
int SpaceshipPower;
int SpaceshipFuel;
int EnemyArmor;
int EnemyPower;
int EnemyFuel;
Điều này sẽ là rối tung mọi thứ rất nhanh, và làm cho nó rất khó để quản lý mã của bạn.
Sử dụng lớp và cấu trúc sẽ làm cho cuộc sống của bạn đơn giản hơn khi đóng gói các dữ liệu đó vào
những gói dữ liệu “rất dễ sử dụng”.
Tạo ra Lớp và Cấu trúc
Về cơ bản, ý tưởng đằng sau lớp và cấu trúc là tạo ra kiểu đối tượng cho riêng bạn bằng những đối
tượng đã có sẵn. Một cấu trúc (structure) là một kiểu dữ liệu mà có thể giữ các dữ liệu khác ở bên
trong, cho phép bạn xây dựng kiểu dữ liệu của riêng bạn. Ví dụ, đây là một cấu trúc mô tả một đối
tượng tàu vũ trụ đơn giản trong C#:
struct Spaceship
{
public int fuel;
public int armor;
public int power;
}
Ghi chú
Từ khóa public nói cho trình biên dịch rằng bất kỳ hàm nào ở bất cứ đâu đầu có thể truy cập
dữ liệu bên trong một cấu trúc. Bạn không phải lo về việc này; tôi sẽ đi sâu hơn vào điều này
trong những mục sau. Nếu public bị bỏ đi, thì máy vi tính sẽ xem rằng bạn không muốn thứ gì
bên ngoài truy cập nó.
Ghi chú
Để tạo một lớp, đơn giản hãy thay từ khóa struct thành class trong ví dụ trước.
Và bậy giờ, bên trong chương trình của bạn, bạn có thể tạo biến tàu vũ trụ cho riêng bạn:
Spaceship player;
Spaceship enemy;
player.fuel = 100;
enemy.fuel = 100;
Điều này đơn giản, phải không?
Sự khác nhau giữa Cấu trúc và Lớp
Trong C#, có một vài điều khác nhau cơ bản giữa cấu trúc và lớp. Cấu trúc thường đơn giản và không
có nhiều thứ phức tạp bên trong chúng. Cấu trúc thường nhỏ hơn lớp, và C# luôn tạo cấu trúc là kiểu
giá trị (nghĩa là chúng sẽ luôn luôn tạo trong ngăn xếp).
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 5
Lớp, khác với cấu trúc, luôn luôn là kiểu tham chiếu, và luôn được tạo trên một đống (heap), thay vì
trên ngăn xếp. Lớp có nhiều thứ mà cấu trúc không có, tôi sẽ giải thích những thứ này khi chúng ta
gặp nó.
Đưa Hàm (Function) và Lớp và Cấu trúc
Lớp và cấu trúc không chỉ có tính năng lưu trữ dữ liệu, mà chúng còn có thể thực hiện một vài phép
tính nữa, nếu bạn cho chúng khả năng đó. Ví dụ, bạn muốn đặt lại mọi dữ liệu của tàu thành 100 một
cách nhanh chóng; nếu không có một hàm, nó trông giống đoạn mã sau:
player.fuel = 100;
player.armor = 100;
player.power = 100;
Rõ ràng, điều này không phải là thứ bạn chỉ làm một lần, vì vậy tại sao thay vào đó không cho nó vào
một hàm, nên lớp Spaceship sẽ trông như thế này (phần mới được tô đậm):
struct Spaceship
{
public int fuel;
public int armor;
public int power;
public void Recharge()
{
fuel = 100;
armor = 100;
power = 100;
}
}
Bây giờ bạn có thể chỉ cần gọi hàm Recharge trên tàu vũ trụ của bạn khi bạn muốn đặt lại tất cả cái
biến:
player.Recharge();
Trả về giá trị
Các hàm không chỉ trhực hiện các tác vụ, mà chúng còn có thể trả về giá trị. Ví dụ, hãy nói bạn có
một con tàu vũ trụ; bạn biết nhiên liệu và năng lượng nó có, nhưng bạn không thực sự chắc chắn về
thời gian mà năng lượng cung cấp sẽ hết. Để tính toán nó, bạn cần thiết lập một công thức – hãy nói
rằng mỗi đơn vị năng lượng duy trì được hai giờ; và bạn muốn tìm xem còn bao nhiêu thời gian với số
năng lượng còn lại, bạn sẽ làm điều gì đó như thế này:
int hoursleft = player.power * 2;
Đó là một cách để giải quyết vấn đề, nhưng đó không thực sự là một giải pháp tốt. Về sau, bạn có thể
đề nghị mỗi đơn vị năng lượng tương đương với ba giờ thay vì hai. Để thay đổi điều này, bạn phải dò
hết lại mã của bạn và tìm xem chỗ nào bạn sử dụng số 2 và thay nó bằng số 3. Không vui chút nào.
Vì vậy, hãy đưng quá trình này vào một hàm!
int HoursofPowerLeft()
{
return power * 2;
}
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 6
Ta-da! Chữ int trước tên hàm nói cho máy vi tính biết kiểu dữ liệu nào sẽ được trả về từ hàm, và bạn
sử dụng từ khóa return để trả về một giá trị. Nếu bạn không muốn trả về cái gì, thì hãy sử dụng
void, như bạn đã thấy trước đó.
Bạn nên ghi chú rằng mệnh đề return sẽ làm cho hàm kết thúc ngay lập tức. Nếu bạn nhìn vào đoạn
mã sau, bạn sẽ thấy một số chúng sẽ không bao giờ được thực thi:
int Function()
{
return 0;
int x = 10; // Dòng này không bao giờ được thực thi
}
Ghi chú
Bạn nên ghi chú rằng trình biên dịch C# đủ thông minh để nhận ra là đoạn mã đó sẽ không
thực thi, và nó sẽ hét lên khi bạn viết mã kiểu đó.
Bạn cũng có thể có nhiều câu lệnh return trong mã của bạn:
int Function()
{
if( something )
return 0;
return 1;
}
Trong đoạn mã này, nếu something là true, thì 0 được trả về; nếu không, 1 được trả về (và thoát,
tất nhiên).
Thông số
Bạn cũng có thể đưa một hàm một vài thông số. Ví dụ của tôi về tính thời gian còn lại dựa trên số
năng lượng còn lại là một phép tính rất đơn giản không sử dụng bất kỳ tham số nào, nhưng tôi có thể
thay đổi điều này và làm cho nó linh hoạt hơn.
Điều gì xảy ra nếu năng lượng giảm đi phụ thuộc vào một số tác nhân bên ngoài, như là có bao nhiêu
phóng xạ trong hệ thống? Hãy nói rằng mức độ phóng xạ càng thấp, càng ít năng lượng bị tiêu tốn. Vì
vậy, nếu bạn viết lại hàm trước với ý tưởng này, bạn có:
int HoursofPowerLeft( int radiationlevel )
{
return (power * 2) / radiationlevel;
}
Nếu mức độ phóng xạ là 1 (tôi đang hoàn toàn hư cấu dữ liệu đo được ở đây; hãy xem như là nó có
nghĩa) và năng lượng của bạn là 100, thì số giờ còn lại là 200. Nếu mức độ phóng xạ là 2, thì bạn còn
100 giờ; và nếu là 3, thì bạn chỉ còn 66 giờ.
Bạn sẽ gọi hàm đó như thế này:
int hoursleft = player.HoursofPowerLeft( 1 );
Nhiều thông số
Sẽ có lúc bạn muốn đưa nhiều hơn một thông số, và C# cho phép bạn làm điều đó:
int Function1( int parameter1, float parameter2, double parameter3 )
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 7
Thông số giá trị vs Thông số tham chiếu
Đây là phần hơi lắt léo một chút. Hãy nói bạn có một lớp với hai thông số trông như thế này:
class MyClass
{
public void Function1( int parameter )
{
parameter = 10;
}
public void Function2()
{
int x = 0;
Function1( x );
// X bằng mấy?
}
}
Vậy, x sau đoạn mã này bằng mấy? Là 0 hay là 10? Câu trả lời là 0 bởi vì bạn đưa x vào bằng giá trị.
Điều này có nghĩa là máy vi tính lấy giá trị của x, sao chép nó, vào đặt nó vào một biến mới tên là
parameter; bây giờ, khi parameter thay đổi, chẳng có gì xảy ra với x.
Vậy làm sao bạn có thể đưa vào bằng tham chiếu? Chỉ cần làm hai việc. Thứ nhất, thay đổi khai báo
của Function1:
public void Function1( ref int parameter )
Thứ hai, thay đổi cách gọi hàm như thế này:
Function1( ref x );
Và bây giờ bạn đã đưa vào tham chiếu của x, và giá trị của x sẽ thay đổi.
Bạn nên ghi chú rằng lớp luôn luôn đưa vào bằng tham chiếu. Ví dụ:
public void Function1( Int32 parameter )
Trong hàm này, bất kỳ Int32 nào bạn đưa vào sẽ luôn luôn là tham chiếu, không phải giá trị.
Quá tải hàm
Bạn có thể có một lớp hay một cấu trúc với vài hàm cùng tên. Điều này nghe có vẻ ngu ngốc, nhưng
nó hoạt động khá tốt trong đời thực. Ví dụ, hãy nói bạn có hai cách khác nhau để tính toán quãng
đường đi của một tàu vũ trụ, đưa bởi lượng nhiên liệu còn lại của nói; một cách lấy số hàng hóa mà
tàu đang chở, cách khác thì bỏ qua số hàng hóa và cho bạn kết quả trong một “điều khiện tốt nhất”.
Bạn có thể tạo các hàm như thế này:
public int DistanceLeft( int cargoweight ) // với hàng hóa
{
// Tính toán ở đây
}
public int DistanceLeft() // tối ưu, không hàng hóa
{
// Tính toán ở đây
}
sau đó bạn có thể gọi chúng thế này:
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 8
int distance;
distance = player.DistanceLeft( 100 );
distance = player.DistanceLeft();
Bạn có thể quá tải hàm bao nhiều lần tùy thích; điều hạn chế duy nhất là mỗi hàm quá tải phải có chữ
ký khác nhau. Chữ ký được định nghĩa là các thông số mà bạn đưa vào, không phải giá trị trả về.
Vì vậy bạn có thể làm thế này:
void Function1();
void Function1( int p1 );
void Function1( float p1, int p2 );
Và bạn cũng có thể làm thế này:
int Function1();
void Function1( int p1 );
float Function2( float p1, int p2 );
Nhưng hoàn toàn không thể làm thế này:
int Function1();
float Function1(); // cùng chữ ký! LỖI!
Hàm xây dựng (Constructor)
Hàm xây dựng là một thứ rất có ích trong hầu hết các ngôn ngữ lập trình hiện đại. Chúng cho phép
bạn tự động khởi tạo lớp và cấu trúc của bạn.
Quay về những ngày xa xưa, khi bạn tạo một lớp hay cấu trúc mới, bạn thật sự không biết cái gì bên
trong nó. Như bạn thấy, máy vi tính không xóa đi bộ nhớ, vì vậy khi bạn ngưng sử dụng một mảnh
của bộ nhớ, máy vi tính chỉ đánh dấu là nó không được sử dụng nữa, và sắp nó ở vị trí đầu tiên trong
danh mục tái sử dụng, với cùng dữ liệu mà nó đã lưu trước đó. Điều này có nghĩa là bạn thường sẽ có
các cấu trúc đầy dữ liệu rác không có nghĩa, và nó có thể gây rất nhiều vấn đề nếu bạn bắt đầu sử
dụng các cấu trúc đó mà không kiểm tra nó có giá trị hợp lệ hay không.
Hàm xây dựng là những hàm cơ bản mà C# sẽ gọi tự động khi bạn tạo một lớp mới.
Hàm xây dựng mặc định (Default Constructor)
Đây là một ví dụ đơn giản của một hàm xây dựng trong một lớp:
class Spaceship
{
public int fuel;
public Spaceship() // Hàm xây dựng mặc định
{
fuel = 100;
}
}
Đoạn mã đậm là cái được gọi là hàm xây dựng mặc định. Khi nào bạn tạo một tàu vũ trụ mới, hàm
Spaceship (ghi chú là nó có cùng tên với lớp) sẽ tự động được gọi.
Mã này tạo ra một tàu vũ trụ với nhiên liệu là 100:
Spaceship s = new Spaceship();
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 9
Hàm xây dựng không mặc định (Non-default Constructor)
Như những hàm bình thường, hàm xây dựng cũng có những phiên bản quá tải, mà nó rất hữu dụng khi
bạn cần cung cấp thêm dữ liệu khi tạo một lớp. Đây là một ví dụ cho thấy làm thế nào để tạo một hàm
xây dựng không mặc định đưa vào một biến chỉ lượng nhiên liệu để gán cho tàu vũ trụ:
public Spaceship( int p_fuel )
{
fuel = p_fuel;
}
Về khi bạn tạo một tàu vũ trụ, bạn có thể gọi hàm xây dựng mới này như thế này:
Spaceship s = new Spaceship( 50 ); // tạo một tàu với 50% nhiên liệu
Bạn có thể tạo bao nhiêu hàm xây dựng tùy thích, miễn là chúng có chữ ký khác nhau.
Cấu trúc và Hàm xây dựng
Cấu trúc cũng có thể có hàm xây dựng, nhưng có một điều: Các cấu trúc không thể có hàm xây dựng
mặc định. Microsoft tuyên bố như thế bởi vì cấu trúc phải nhẹ. Vì vậy cấu trúc có thể có hàm xây
dựng khô mặc định, nhưng không thể có hàm xây dựng mặc định.
Hàm phá hủy (Destructor)
Nếu hàm xây dựng được gọi bất cứ khi nào lớp được tạo, thì hàm phá hủy được gọi bất cứ khi nào
một lớp bị loại bỏ. Trong những ngôn ngữ cụ như C++, hàm phá hủy rất quan trọng bởi vì bạn luôn
luôn phải giải phóng bộ nhớ mà bạn không sử dụng nữa. Nhưng từ khi xuất hiện bộ thu gom rác, hàm
phá hủy đã gần như đi theo lối của khủng long. Chúng thật sự không được sử dụng nhiều nữa, nhưng
vẫn được thêm vào để đề phóng.
Ví dụ cơ bản
Một hàm phá hủy trông giống thế này:
class MyClass
{
~MyClass()
{
// Mã ở đây
}
}
Trong những ngôn nhữ giống C++, đây là nơi mà bạn sẽ tạo một hàm tự động dọn dẹp bộ nhớ cho bạn
nếu nó có yêu cầu. Nhưng .NET runtime sẽ lo tất cả những vấn đề bộ nhớ này cho bạn, bạn thực sự
không cần phải làm như trên.
Sự phá hủy bị trì hoãn
Một điều khác về hàm phá hủy là chúng không được gọi ngay tức thời. Ví dụ, hãy nhìn đoạn mã này:
Spaceship s = new Spaceship(); // tàu vũ trụ mới
s = null; // tham chiếu đến tàu vũ trụ bị mất
Trong đoạn mã này, một tàu vũ trụ mới được tạo và một tham chiếu đến nó được gán cho s. Tuy
nhiên, trên dòng tiếp theo, tham chiếu được đặt về null, nhưng hệ thống có thể giữ vùng nhớ đó một
thời gian dài sau khi bạn đặt lại tham chiếu.
Câu lạc bộ Khoa học - THPT Chuyên Lê Hồng Phong TPHCM LHPSC
Lập trình C# - Phần 3: Giới thiệu về Lớp Trang 10
Do đó, vấn đề chính với hàm phá hủy là bạn thật sự không biết khi nào chúng được gọi. Bạn không
thể làm một lớp bị phá hủy ngay tức thời, vì vậy đừng nói rằng là nó sẽ bị phá hủy khi bạn xóa hết
mọi tham chiếu.
Còn nhiều thứ khác về hàm phá hủy, nhưng dù sao bạn cũng không sử dụng chúng nhiều. Nên đừng
bận tâm tới chúng.
Ghi chú
Cấu trúc không có hàm phá hủy vì chúng là những thứ rất nhẹ.
Các thủ thuật nâng cao về Lớp
Hiện nay, bạn đã có vẻ quen với các lớp và bạn có thể tạo ra một cái để thực hiện những tác vụ nhỏ
như lưu trữ dữ liệu và thực hiện phép tính đơn giản. Tuy nhiên, lớp còn có nhiều điều mà bạn chưa
thấy.
Cơ bản về thừa kế (Inheritance)
Một trong những ưu điểm lớn nhất của ngôn ngữ lập trình hướng đối tượng là sự thừa kế. Tôi sẽ
không đi sâu vào chủ đề thừa kế, nhưng bạn nên hiểu và có thể sử dụng sự thừa kế sau khi đọc xong
cuốn sách này.
Sự thừa kế cho phép bạn tạo chương trình của bạn theo một cách thực tế, vì khả năng phân cấp sẽ làm
cho lớp của bạn giống như đối tượng trong đời thực. Cách dễ nhất để nghĩ về sự thừa kế là nghĩ về sự
phân lớp của động vật.
Một ví dụ về Thừa kế
Nếu bạn nhớ về môn sinh học thời trung học, thì bạn biết các lòa thú đều có một số đặc điểm chung,
nhưng sinh ra con và có tim bốn ngăn. Trong một chương trình máy vi tính, bạn có thể tạo ra lớp thú
của bạn và cho nó những đặc điểm này.
Nhưng dù mọi loài thú chia sẽ chung một số đặc điểm, chúng lại không chia sẻ hết mọi đặc điểm. Con
người có hai chân