Lập trình C#

Hàm dựng (constructor) và tính kế thừa trong C#

Hàm dựng (constructor) và tính kế thừa trong 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ẽ.

Hàm dựng (constructor) và tính kế thừa trong C#

Qua bài viết trước, chúng ta đã hiểu được tính kế thừa trong lập trình C#. Trong bài này sẽ bổ sung hoàn chỉnh với nội dung trình bày về cách sử dụng hàm dựng constructor trong kế thừa:

Nhắc lại Tính kế thừa
Nhắc lại Tính kế thừa

Giả sử chúng ta có một lớp cơ sở Hình Học và hai lớp dẫn xuất là Hình Chữ NhậtHình Vuông như sau:

– Lớp cơ sở Hình học : có các thuộc tính Chiều dài, Chiều rộng, và các phương thức Set chiều dài, Set chiều rộng.

– Hai lớp dẫn xuất là Hình Chữ NhậtHình Vuông : ngoài việc kế thừa các thuộc tính và phương thức của lớp cha Hình Học, thì hình chữ nhật và hình vuông sẽ có cách tính chu vi và diện tích là khác nhau nên ở mỗi lớp sẽ xây dựng thêm 2 phương thức riêng là Tính chu viTính diện tích.

Inheritance: Shape - Rectangle - Square

Inheritance: Shape – Rectangle – Square

– Chúng ta sẽ cài đặt như sau:

(*) Ví dụ ①

[code language=”csharp” highlight=”10,13,14,21,24,37,59,76″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// ① Tạo đối tượng hình chữ nhật
HinhChuNhat hcn = new HinhChuNhat();

// Sử dụng phương thức kế thừa từ lớp cha
hcn.setChieuRong(8);
hcn.setChieuDai(9);

// In Chu vi và Diện tích của hình chữ nhật
Console.WriteLine("Chu vi hinh chu nhat: {0}", hcn.TinhChuVi());
Console.WriteLine("Dien tich hinh chu nhat: {0}", hcn.TinhDienTich());

// ② Tạo đối tượng hình vuông
HinhVuong hv = new HinhVuong();

// Sử dụng phương thức kế thừa từ lớp cha
hv.setChieuDai(19);

// In Chu vi và Diện tích của hình vuông
Console.WriteLine("Chu vi hinh vuong: {0}", hv.TinhChuVi());
Console.WriteLine("Dien tich hinh vuong: {0}", hv.TinhDienTich());

Console.ReadKey();
}
}

/// <summary>
/// Class cơ sở Hình Học
/// </summary>
class HinhHoc
{
// Thuộc tính dùng chung
protected int ChieuDai;

protected int ChieuRong;

// Phương thức dùng chung
public void setChieuDai(int inChieuDai)
{
ChieuDai = inChieuDai;
}

public void setChieuRong(int inChieuRong)
{
ChieuRong = inChieuRong;
}
}

/// <summary>
/// Class dẫn xuất Hình Chữ Nhật
/// </summary>
class HinhChuNhat : HinhHoc // Kế thừa
{
public int TinhChuVi()
{
// Sử dụng thuộc tính ChieuDai, ChieuRong kế thừa từ lớp cha
return (ChieuDai + ChieuRong) * 2;
}

public int TinhDienTich()
{
return (ChieuDai * ChieuRong);
}
}

/// <summary>
/// Class dẫn xuất Hình Vuông
/// </summary>
class HinhVuong : HinhHoc // Kế thừa
{
public int TinhChuVi()
{
// Sử dụng thuộc tính ChieuDai kế thừa từ lớp cha
return (ChieuDai * 4);
}

public int TinhDienTich()
{
return (int)Math.Pow(ChieuDai, 2);
}
}
}
[/code]

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

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

Hàm dựng Constructor trong kế thừa
Hàm dựng Constructor trong kế thừa

– Khi chúng ta tạo một đối tượng từ lớp con thì hàm dựng Constructor của lớp cha sẽ được gọi trước, được thực hiện trước, sau đó thì hàm dựng Constructor của lớp con mới được gọi thực thi (Nôm na là phải có cha rồi mới có con, nên hàm của cha sẽ được thực hiện trước). Chúng ta xét ví dụ sau:

[code language=”csharp” highlight=”10,24,38″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Tạo đối tượng hình chữ nhật
HinhChuNhat hcn = new HinhChuNhat();

Console.ReadKey();
}
}

/// <summary>
/// Class cơ sở Hình Học
/// </summary>
class HinhHoc
{
/// <summary>
/// Constructor
/// </summary>
public HinhHoc()
{
Console.WriteLine( "Constructor base class HinhHoc." );
}
}

/// <summary>
/// Class dẫn xuất Hình Chữ Nhật
/// </summary>
class HinhChuNhat : HinhHoc // Kế thừa
{
/// <summary>
/// Constructor
/// </summary>
public HinhChuNhat()
{
Console.WriteLine( "Constructor derived class HinhChuNhat." );
}
}
}
[/code]

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

Constructor base class HinhHoc.

Constructor derived class HinhChuNhat.

Trong C#, khi một class được tạo ra, nếu class đó chưa có Constructor, Visual C# sẽ ngầm định tự động generate một constructor mặc định (không tham số), vì nếu không làm vậy sẽ không thể tạo một object mới thuộc class đó rồi, như các bạn thấy ở ví dụ ① chúng ta có thể tạo ra các đối tượng HinhChuNhat, HinhVuong mà không cần tạo hàm Constructor.

Vậy trong trường hợp Constructor có tham số thì sẽ khai báo thế nào?

– Bây giờ chúng ta sẽ xét ví dụ sau có khai báo constructor có tham số ở lớp cha:

(*) Ví dụ ②

[code language=”csharp” highlight=”9,10,42-51″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Tạo đối tượng hình chữ nhật, sử dụng constructor không tham số
HinhChuNhat hcn = new HinhChuNhat();

// Sử dụng phương thức kế thừa từ lớp cha
hcn.setChieuRong(8);
hcn.setChieuDai(9);

// In Chu vi và Diện tích của hình chữ nhật
Console.WriteLine("Chu vi hinh chu nhat: {0}", hcn.TinhChuVi());
Console.WriteLine("Dien tich hinh chu nhat: {0}", hcn.TinhDienTich());

Console.ReadKey();
}
}

/// <summary>
/// Class cơ sở Hình Học
/// </summary>
class HinhHoc
{
// Thuộc tính dùng chung
protected int ChieuDai;

protected int ChieuRong;

/// <summary>
/// Constructor không tham số
/// </summary>
public HinhHoc()
{
Console.WriteLine( "Constructor base class HinhHoc." );
}

/// <summary>
/// Constructor có tham số
/// </summary>
/// <param name="cd">Chiều dài</param>
/// <param name="cr">Chiều rộng</param>
public HinhHoc(int cd, int cr)
{
ChieuDai = cd;
ChieuRong = cr;
}

// Phương thức dùng chung
public void setChieuDai(int inChieuDai)
{
ChieuDai = inChieuDai;
}

public void setChieuRong(int inChieuRong)
{
ChieuRong = inChieuRong;
}
}

/// <summary>
/// Class dẫn xuất Hình Chữ Nhật
/// </summary>
class HinhChuNhat : HinhHoc // Kế thừa
{
/// <summary>
/// Constructor không tham số
/// </summary>
public HinhChuNhat()
{
Console.WriteLine( "Constructor derived class HinhChuNhat." );
}

public int TinhChuVi()
{
// Sử dụng thuộc tính ChieuDai, ChieuRong kế thừa từ lớp cha
return (ChieuDai + ChieuRong) * 2;
}

public int TinhDienTich()
{
return (ChieuDai * ChieuRong);
}
}
}
[/code]

Đối với trường hợp ở lớp cha KHÔNG khai báo constructor có tham số thì việc khai báo constructor không tham số ở lớp con có hay không cũng không sao cả. Chương trình vẫn chạy bình thường như ví dụ ①.

Đối với trường hợp ở lớp cha CÓ khai báo constructor có tham số như ví dụ ②, thì sẽ có 2 trường hợp xảy ra:

Trường hợp 1: Lớp cha có khai báo constructor không tham số
Chương trình ở ví dụ ② sẽ chạy được bình thường, vì khi tạo đối tượng hình chữ nhật, là chúng ta đang sử dụng constructor không tham số:

HinhChuNhat hcn = new HinhChuNhat();

Trường hợp 2: Lớp cha không khai báo constructor không tham số

– Nếu comment constructor không tham số ở lớp cha Hình học thì constructor không tham số ở lớp con Hình chữ nhật sẽ báo lỗi, vì lúc này nó không có constructor không tham số ở lớp cha base() để kế thừa.

*** Vì bản chất 2 cách viết bên dưới là tương đương nhau:

[code language=”csharp” highlight=”4″] /// <summary>
/// Constructor
/// </summary>
public HinhChuNhat()
{
Console.WriteLine( "Constructor derived class HinhChuNhat" );
}
[/code]

Hoặc:

[code language=”csharp” highlight=”4″] /// <summary>
/// Constructor
/// </summary>
public HinhChuNhat() : base()
{
Console.WriteLine( "Constructor derived class HinhChuNhat" );
}
[/code]

Comment hàm constructor không tham số ở lớp cha thì base() sẽ không còn tồn tại. Do đó constructor không tham số ở lớp con sẽ báo lỗi.

Comment hàm constructor không tham số ở lớp cha thì base() sẽ không còn tồn tại. Do đó constructor không tham số ở lớp con sẽ báo lỗi.

Do đó trong trường hợp ở lớp cha có constructor có tham số, mà không khai báo constructor không tham số thì ở lớp con bắt buộc phải khai báo một constructor có tham số.

– Chương trình ở ví dụ ② sẽ được viết lại như sau:

[code language=”csharp” highlight=”9,10,35-39,50-53″] using System;

namespace MinhHoangBlog
{
class Program
{
static void Main(string[] args)
{
// Tạo đối tượng hình chữ nhật, sử dụng constructor có tham số
HinhChuNhat hcn = new HinhChuNhat(8, 9);

// In Chu vi và Diện tích của hình chữ nhật
Console.WriteLine("Chu vi hinh chu nhat: {0}", hcn.TinhChuVi());
Console.WriteLine("Dien tich hinh chu nhat: {0}", hcn.TinhDienTich());

Console.ReadKey();
}
}

/// <summary>
/// Class cơ sở Hình Học
/// </summary>
class HinhHoc
{
// Thuộc tính dùng chung
protected int ChieuDai;

protected int ChieuRong;

/// <summary>
/// Constructor có tham số
/// </summary>
/// <param name="cd">Chiều dài</param>
/// <param name="cr">Chiều rộng</param>
public HinhHoc(int cd, int cr)
{
ChieuDai = cd;
ChieuRong = cr;
}
}

/// <summary>
/// Class dẫn xuất Hình Chữ Nhật
/// </summary>
class HinhChuNhat : HinhHoc // Kế thừa
{
/// <summary>
/// Constructor có tham số
/// </summary>
public HinhChuNhat(int cd, int cr) : base(cd, cr)
{
// Tùy vào logic cụ thể Có thể có hoặc không có xử lý ở đây.
}

public int TinhChuVi()
{
// Sử dụng thuộc tính ChieuDai, ChieuRong kế thừa từ lớp cha
return (ChieuDai + ChieuRong) * 2;
}

public int TinhDienTich()
{
return (ChieuDai * ChieuRong);
}
}
}
[/code]

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

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

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!

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 bạn đọ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[...]

7 bình luận

Translate »