Làm sao để lưu trữ các biến đã khai báo để khi cần thì có thể dùng tới?
Ta có thể hình dung rằng một biến có các thuộc tính như Danh biểu (Identifier), Kiểu dữ liệu (Type), các giá trị kiểu int, float, và string. Nhiều thuộc tính như vậy thì dùng cấu trúc (struct) là hợp nhất.
Nhưng cấu trúc biến sẽ không bao gồm danh biểu trong đó. Tại vì cấu trúc này không chỉ đơn thuần để chứa thông tin của một biến được khai báo cho chương trình. Nó còn có thể được dùng để lưu các giá trị trong quá trình tính toán biểu thức, sau rốt lưu giá trị của biểu thức đó để sử dụng cho các việc khác.
Ta sẽ đặt tên cho cấu trúc này là Record. Cấu trúc Record ban đầu sẽ trông như sau:
Syntax: [ Download ] [ Hide ] [ Select ] [ Contract ]
Using csharp Syntax Highlighting
public struct Record {
// Kiểu dữ liệu (một kiểu enum)
private int mIntValue;
private float mFloatValue;
private string mStringValue;
}
Parsed in 0.007 seconds, using GeSHi 1.0.8.4
Bây giờ cần thêm mắm dặm muối mới vừa ăn. Cái đầu tiên cần thêm chính là các hàm tạo lập. Bạn sẽ cần tới chúng sau này:
Syntax: [ Download ] [ Hide ] [ Select ] [ Contract ]
Using csharp Syntax Highlighting
public Record(int value) {
this.Type = DataType.Int;
this.mIntValue = value;
this.mFloatValue = 0f;
this.mStringValue = string.Empty;
}
public Record(float value) {
this.Type = DataType.Float;
this.mIntValue = 0;
this.mFloatValue = value;
this.mStringValue = string.Empty;
}
public Record(string value) {
this.Type = DataType.String;
this.mIntValue = 0;
this.mFloatValue = 0f;
this.mStringValue = value;
}
Parsed in 0.009 seconds, using GeSHi 1.0.8.4
Các thuộc tính liên quan tới giá trị của Record cũng sẽ thể hiện nguyên tắc chuyển kiểu mà ta vừa đưa ra:
Syntax: [ Download ] [ Hide ] [ Select ] [ Contract ]
Using csharp Syntax Highlighting
// Giá trị kiểu int
public int IntValue {
get {
switch (this.Type) {
case DataType.Int:
return this.mIntValue;
case DataType.Float:
return (int)this.mFloatValue;
default: //string return 0; } } set {
this.Type = DataType.Int;
this.mIntValue = value;
this.mFloatValue = 0f;
this.mStringValue = string.Empty;
} }
// Giá trị kiểu float
public float FloatValue {
get {
switch (this.Type) {
case DataType.Int:
return this.mIntValue;
case DataType.Float:
return this.mFloatValue;
default: //string return 0f; } } set {
this.Type = DataType.Float;
this.mIntValue = 0;
this.mFloatValue = value;
this.mStringValue = string.Empty;
} }
// Giá trị kiểu string
public string StringValue {
get {
switch (this.Type) {
case DataType.Int:
return this.mIntValue.ToString();
case DataType.Float:
return this.mFloatValue.ToString();
default: //string
return this.mStringValue;
} }
set {
this.Type = DataType.String;
this.mIntValue = 0;
this.mFloatValue = 0f;
this.mStringValue = value;
} }
Parsed in 0.014 seconds, using GeSHi 1.0.8.4
Bây giờ mời bạn gặp gỡ operator overload. Trong các sách, người ta thường dịch là "nạp chồng toán tử", hoặc "quá tải toán tử". Riêng tôi thích cách gọi định nghĩa bội toán tử hơn. Chẳng có "chồng" hay "tải" gì ở đây hết!
Chúng ta sẽ định nghĩa các toán tử cho cấu trúc Record. Nhờ vào đó, mai mốt khi làm một phép toán giữa hai biến kiểu Record, ta chỉ cần ghi theo lối tính toán hai con số bình thường.
Syntax: [ Download ] [ Hide ] [ Select ] [ Contract ]
Using csharp Syntax Highlighting
// Phép cộng
public static Record operator +(Record lhs, Record rhs) {
// Cộng chuỗi thì cũng như ghép chuỗi
// Chỉ cấn có 1 toán hạng kiểu chuỗi là được
if (lhs.Type == DataType.String || rhs.Type == DataType.String) return new Record(lhs.StringValue + rhs.StringValue);
else if (lhs.Type == DataType.Float || rhs.Type == DataType.Float) return new Record(lhs.FloatValue + rhs.FloatValue);
else
return new Record(lhs.IntValue + rhs.IntValue);
}
// Phép trừ
public static Record operator -(Record lhs, Record rhs) {
if (lhs.Type == DataType.String || rhs.Type == DataType.String) return new Record(0);
else if (lhs.Type == DataType.Float || rhs.Type == DataType.Float) return new Record(lhs.FloatValue - rhs.FloatValue);
else
return new Record(lhs.IntValue - rhs.IntValue);
// Phép đổi dấu
public static Record operator -(Record rhs) {
if (rhs.Type == DataType.String) return new Record(0);
else if (rhs.Type == DataType.Float) return new Record(-rhs.FloatValue);
else
return new Record(-rhs.IntValue);
}
// Phép nhân
public static Record operator *(Record lhs, Record rhs) {
if (lhs.Type == DataType.String || rhs.Type == DataType.String) return new Record(0);
else if (lhs.Type == DataType.Float || rhs.Type == DataType.Float) return new Record(lhs.FloatValue * rhs.FloatValue);
else
return new Record(lhs.IntValue * rhs.IntValue);
}
// Phép chia
public static Record operator /(Record lhs, Record rhs) {
if (lhs.Type == DataType.String || rhs.Type == DataType.String) return new Record(0);
// Nếu toán tử trái là float thì kết quả là float
if (lhs.Type == DataType.Float)
return new Record(lhs.FloatValue / rhs.FloatValue);
// Còn không thì kết quả là int
else
return new Record(lhs.IntValue / rhs.IntValue);
}
// Phép chia lấy phần dư
public static Record operator %(Record lhs, Record rhs) {
if (lhs.Type == DataType.String || rhs.Type == DataType.String) return new Record(0);
else
return new Record(lhs.IntValue % rhs.IntValue);
}
// Phép lũy thừa
// Trong ngôn ngữ họ nhà C không có toán tử lũy thừa // Cái này là ăn gian cho tiện lợi vậy thôi!
public Record Pow(Record rhs) {
if (this.Type == DataType.String || rhs.Type == DataType.String) return new Record(0);
else if (this.Type == DataType.Float || rhs.Type == DataType.Float)
return new Record((float)Math.Pow(this.FloatValue, rhs.FloatValue));
else
return new Record((int)Math.Pow(this.IntValue, rhs.IntValue));
}
Parsed in 0.023 seconds, using GeSHi 1.0.8.4