Lập trình hướng đối tượng (OOP) trong C – cách tạo đối tượng trong c

Trong hướng dẫn C / C ++ trung cấp này, bạn sẽ học cách mang một số phong cách lập trình hướng đối tượng sang C, một ngôn ngữ không có hỗ trợ OOP tích hợp sẵn.

Bạn đang xem : cách tạo đối tượng trong c

Tổng quan

Các ngôn ngữ lập trình như C ++ và Java có hỗ trợ tích hợp cho các khái niệm OOP. Tuy nhiên, bạn có biết rằng bạn không cần sử dụng ngôn ngữ OOP để sử dụng kiểu OOP và nhận được một số lợi ích của lập trình hướng đối tượng? Trong hướng dẫn này, tôi sẽ giải thích cách chúng ta có thể mang một số phong cách lập trình hướng đối tượng sang C, một ngôn ngữ không có hỗ trợ OOP tích hợp sẵn.

Các loại đơn giản, không đa hình

Hãy xem xét một lớp đơn giản không thể bị ghi đè (không có phương thức ảo):

 

class

Điểm

{

công khai

: Point (

int

x,

int

y); ~ Điểm ();

int

x

()

const

;

int

y

()

const

;

riêng tư

:

const

int

x_;

const

int

y_; }; Point :: Point (

int

x,

int

y): x_ (x), y_ (y) { } Điểm :: ~ Điểm () {}

int

Điểm :: x

()

const

{

return

x_; }

int

Điểm :: y

()

const

{

return

y_; }

Tiêu đề cho điều này có thể được dịch sang C như sau:

 

struct

Điểm

;

Point *

Point__create

(

int < / p> x,

int

y)

;

void

Point__destroy

(Điểm * bản thân)

;

int

Point__x

(Điểm * bản thân)

;

int

Point__y

(Điểm * bản thân)

;

Có một số điểm quan trọng cần lưu ý về bản dịch này. Thứ nhất, chúng tôi không chỉ rõ định nghĩa đầy đủ của “Point” để đạt được tính đóng gói; chúng tôi giữ “x” và “y” một cách hiệu quả là “riêng tư” bằng cách xác định đầy đủ “Điểm” chỉ trong tệp nguồn. Thứ hai, chúng tôi tạo các hàm tương ứng với hàm tạo / hủy cộng với cấp phát / định vị thỏa thuận thay thế “mới” và “xóa”. Thứ ba, tất cả các hàm thành viên nhận được một tham số rõ ràng là “self” của kiểu đang được vận hành (thay thế cho tham số ngầm “this”).

Tệp nguồn cho các khai báo ở trên có thể giống như sau:

 

struct

Điểm

{

int

x;

int

y; };

void

Point__init

(Point * self,

int

x,

int

y)

{ tự- & gt; x = x; tự & gt; y = y; }

Point *

Point__create

(

int < / p> x,

int

y)

{ Point * result = (Point *)

malloc

(

sizeof

(Point)); Point__init (kết quả, x, y);

trả về kết quả

; }

void

Point__reset

(Điểm * bản thân)

{ }

void

Point__destroy

(Điểm*

point

)

{

if

(

point

) { Point__reset (

point

);

free

(

point

); } }

int

Point__x

(Điểm * bản thân)

{

trả về

self- & gt; x; }

int

Point__y

(Điểm *

point

)

{

trả về

tự & gt; y; }

Các mẫu áp dụng cho các đối tượng đơn giản cũng được áp dụng cho các loại đối tượng khác, nhưng chúng tôi thêm một số cải tiến để giải quyết các khái niệm như đa hình và kế thừa.

Các loại đa hình

Để tạo các kiểu đa hình trong C, chúng ta cần bao gồm thông tin kiểu bổ sung trong các đối tượng của mình và chúng ta cần một số cách ánh xạ từ thông tin kiểu đó đến tùy chỉnh mà kiểu yêu cầu. Để minh họa điều này, hãy xem xét:

 

class

Hình dạng

{

công khai

:

ảo

~ Hình dạng () {}

ảo

const

char

*

name

()

const

=

0

;

ảo

int

các bên

()

const

=

0

; };

class

Hình vuông

:

công khai

Hình dạng {

công khai

: Hình vuông (

int

x,

int

y,

int width,

int

height) : x_ (x), y_ (y), width_ (chiều rộng), height_ (chiều cao) {}

virtual

~ Square () {}

const

char

*

tên

()

const

ghi đè

{

return

"Hình vuông"

; }

int

bên

()

const

ghi đè

{

trả về

4

; }

int

x

()

const

{

return

x_; }

int

y

()

const

{

return

y_; }

int

width

()

const

{

return

width_; }

int

height

()

const

{

return

height_; }

riêng tư

;

int

x_;

int

y_;

int

width_;

int

height_; };

Đối với lớp cơ sở Shape, chúng ta có thể khai báo mã C sau:

 

struct

Hình dạng

;

struct

ShapeType

;

ShapeType *

ShapeType__create

(

int

buffer_size,

const

char

* (* name) (Shape *),

int

(* bên) (Hình dạng *),

void

(* tiêu diệt) (Hình dạng *))

;

Shape *

Shape__create

(ShapeType * type)

;

ShapeType *

Shape__type

(Hình dạng * tự)

;

void

*

Shape__buffer

(Hình dạng * bản thân)

;

int

Shape__sides

(Hình dạng * bản thân)

;

void

Shape__destroy

(Hình dạng * hình dạng)

;

Trong đoạn mã trên, hãy lưu ý rằng chúng tôi đã tạo một đối tượng bổ sung đại diện cho kiểu của hình dạng. Thông tin loại này là cách chúng tôi thực hiện điều phối động (tức là cách chúng tôi giải quyết các chức năng ảo). Bạn cũng sẽ lưu ý điều thú vị về “kích thước” này, chúng tôi sử dụng để cho phép Hình dạng được phân bổ thêm không gian cho bộ đệm, chúng tôi sẽ sử dụng để lưu trữ dữ liệu cho lớp con của hình dạng.

Ý tưởng cơ bản là đối với mỗi loại hình (Hình vuông, Hình ngũ giác, Hình lục giác, v.v.), sẽ có chính xác một phiên bản của cấu trúc ShapeType . Có nghĩa là, mọi Square mà chúng tôi tạo sẽ tham chiếu đến cùng một trường hợp chính xác của ShapeType đại diện cho các hình vuông.

Mã triển khai tương ứng cho lớp cơ sở có thể giống như sau:

 

struct

Hình dạng

{

Kiểu ShapeType *;

char

buffer_start; };

struct

ShapeType

{

int

buffer_size;

const

char

* (* name) (Hình dạng *);

int

(* bên) (Hình dạng *);

void

(* tiêu diệt) (Hình dạng *); };

ShapeType *

ShapeType__create

(

int

buffer_size,

const

char

* (* name) (Shape *),

int

(* bên) (Hình dạng *),

void

(* tiêu diệt) (Hình dạng *))

{ ShapeType * result = (ShapeType *)

malloc

(

sizeof

(ShapeType)); result- & gt; buffer_size = buffer_size; kết quả- & gt; name = name; kết quả- & gt; bên = bên; kết quả- & gt; tiêu diệt = tiêu diệt;

trả về kết quả

; }

Shape *

Shape__create

(ShapeType * type)

{

int

size

=

sizeof

(Hình dạng) + type- & gt; buffer_size; Hình dạng * result = (Hình dạng *)

malloc

(

size

); kết quả- & gt; type = type;

trả về kết quả

; }

ShapeType *

Shape__type

(Hình dạng * tự)

{

return

self- & gt; type; }

void

*

Shape__buffer

(Hình dạng * bản thân)

{

return

(

void

*) & amp; (self- & gt; buffer_start); }

int

Shape__sides

(Hình dạng * bản thân)

{

return

self- & gt; type- & gt; side (self); }

void

Shape__destroy

(Hình dạng * hình dạng)

{

nếu

(shape) { shape- & gt; type- & gt; kill (shape); } }

Chức năng của lớp cơ sở có thể trở nên rõ ràng hơn khi chúng ta xem xét một trường hợp dẫn xuất. Khai báo cho một hình vuông có thể giống như sau:

 // square.h
struct Square;
Shape * Square__to_shape (Hình vuông * hình vuông);
Square * Square__from_shape (Hình dạng * hình dạng);
Square * Square__create (int x, int y, int width, int height);
void Square__destroy (Square * hình vuông);

// Tương tự với các trình truy cập trong trường hợp trước
int Square__x (Hình vuông * tự);
int Square__y (Vuông * tự));
int Square__width (Hình vuông * tự);
int Square__height (Hình vuông * tự);

Và định nghĩa tương ứng của nó:

// square.c
struct SquareData {
   int x;
   int y;
   chiều rộng int;
   chiều cao int;
};

const char * Square__name_override (Hình dạng * tự) {
   return "Hình vuông";
}

int Square__sides_override (Hình dạng * tự) {
   trả về 4;
}

void * Square__destroy_override (Hình dạng * hình vuông) {
   miễn phí (hình vuông);
}

static ShapeType * square_type =
       ShapeType__create (
           sizeof (SquareData),
           & amp; Square__name_override,
           & amp; Square__sides_override,
           & amp; Square__destroy_override);

Hình dạng * Square__to_shape (Hình vuông * hình vuông) {
   return ((Hình dạng *) hình vuông);
}

Square * Square__from_shape (Hình dạng * hình dạng) {
  if (! shape) {
    return ((Hình vuông *) 0);
  }

  ShapeType * type = Shape__type (hình dạng);
  if (type! = square_type) {
    return ((Hình vuông *) 0);
  }

  return ((Hình vuông *));
}

SquareData * Square__square_data (Square * tự) {
   Shape * shape = (Hình dạng *) tự;
   return (SquareData *) Shape__buffer (hình dạng);
}

Square * Square__create (int x, int y, int width, int height) {
   Square * result = (Vuông *) Shape__create (kiểu_bình vuông);
   SquareData * square_data = Square__square_data (kết quả);
   dữ liệu hình vuông- & gt; x = x;
   dữ liệu hình vuông- & gt; y = y;
   dữ liệu hình vuông- & gt; width = width;
   square_data- & gt; height = height;
   trả về kết quả;
}

void Square__destroy (Square * hình vuông) {
   Shape__destroy (Square__to_shape (hình vuông));
}

int Square__x (Hình vuông * tự) {
   return Square__square_data (self) - & gt; x;
}

int Square__y (Hình vuông * tự) {
   return Square__square_data (self) - & gt; y;
}

int Square__width (Hình vuông * tự) {
   return Square__square_data (self) - & gt; width;
}

int Square__height (Hình vuông * tự) {
   return Square__square_data (self) - & gt; height;
}
 

Để tóm tắt đoạn mã trên, khi liên quan đến kế thừa / đa hình, cần phải đóng gói các hàm đa hình trong một cấu trúc đại diện cho các kiểu dẫn xuất khác nhau của kiểu cơ sở. Bởi vì các kiểu dẫn xuất cũng có thể thêm nhiều dữ liệu hơn vào đối tượng, thao tác cấp phát phải cho phép các kiểu dẫn xuất yêu cầu thêm không gian. Cũng cần cung cấp các hàm có thể thực hiện truyền lên và truyền xuống giữa các kiểu dữ liệu khác nhau. Ngoài ra, các hàm ảo trong C ++ dịch sang các hàm tìm kiếm và gửi đến việc triển khai theo kiểu được cung cấp của hàm đã cho.

Với những điều trên, bạn có thể hỏi, tại sao lại có thêm lớp chuyển hướng của ShapeType ? Tại sao không chỉ cần lưu trữ các con trỏ hàm đại diện cho hàm ảo ghi đè trực tiếp trên đối tượng Shape (sẽ được cung cấp trong hàm create của các loại dẫn xuất khác nhau).

Điều này được thực hiện vì hiệu quả … việc kết hợp các chức năng ảo khác nhau ghi đè trong một đối tượng loại tồn tại lâu dài riêng biệt cho phép mỗi phiên bản chỉ trả cho một trường con trỏ duy nhất để hỗ trợ tính đa hình; nếu dữ liệu này trực tiếp trên các phiên bản, thì mỗi phiên bản sẽ cần nhiều trường bổ sung vì có các hàm ảo.

Kết luận

Có thể kết hợp dữ liệu với hành vi, đóng gói các trường dữ liệu, kế thừa / đa hình và các khái niệm OOP khác có thể đạt được trong các ngôn ngữ lập trình thiếu hỗ trợ OOP (như C), mặc dù có nhiều bản soạn thảo hơn. Điều này sẽ có ý nghĩa trực quan vì các ngôn ngữ OOP phải / phải được triển khai theo các ngôn ngữ không phải OOP tại một số thời điểm. Mặc dù, trong một số trường hợp, bảng soạn sẵn mà cách tiếp cận này tạo ra có thể không phải lúc nào cũng đáng giá, việc viết mã C bắt buộc theo kiểu OOP có thể làm sáng tỏ cách hoạt động của OOP. Khả năng viết theo kiểu này cũng có giá trị để tạo các API được chia sẻ giữa các ngôn ngữ OOP và không phải OOP.


Xem thêm những thông tin liên quan đến chủ đề cách tạo đối tượng trong c

[C++] – Bài 48: Constructors – Hàm tạo.

  • Tác giả: thân triệu
  • Ngày đăng: 2016-07-01
  • Đánh giá: 4 ⭐ ( 7041 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Hướng dẫn lập trình C++ căn bản. tự học lập trình. classes and objects: hàm tạo của class trong C++. triệu thân channel – let’s grow together!.

    link file .cpp: http://adf.ly/1jQPyR

    file .pptx: http://adf.ly/1jQPEf

Tìm hiểu C# và ứng dụng: Lớp và đối tượng trong C#

  • Tác giả: www.voer.edu.vn
  • Đánh giá: 5 ⭐ ( 3543 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Giới thiệu về lớp và đối tượng trong C# (giáo trình – tài liệu – học liệu từ VOER)

Lập trình hướng đối tượng (OOP) trong C#

  • Tác giả: comdy.vn
  • Đánh giá: 4 ⭐ ( 1853 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Lập trình hướng đối tượng (OOP) trong C# là gì? 5 khái niệm và 4 tính chất quan trọng của lập trình hướng đối tượng là gì?

Constructor (hàm tạo/hàm dựng) trong C#, khởi tạo object

  • Tác giả: tuhocict.com
  • Đánh giá: 5 ⭐ ( 6564 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Bài học này sẽ hướng dẫn bạn cách viết phương thức constructor (hàm tạo, hàm dựng) khi xây dựng class C# và các cách khởi tạo đối tượng cho class trong C#.

Lập trình hướng đối tượng trong C++

  • Tác giả: www.elib.vn
  • Đánh giá: 4 ⭐ ( 7007 lượt đánh giá )
  • Khớp với kết quả tìm kiếm:

[C/C++] – Bài 14: Lập trình hướng đối tượng trong C++ (OOP)

  • Tác giả: www.tbit.vn
  • Đánh giá: 4 ⭐ ( 6905 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: * TÓM TẮT LÝ THUYẾT

    1. Giới thiêu lập trình hướng đối tượng (OOP) với C++
    – C++ là ngôn ngữ “lai” giữa lập trình Cấu trúc và Lập trình hướng đối…

Chi tiết bài học Lớp và đối tượng trong C++

  • Tác giả: vimentor.com
  • Đánh giá: 4 ⭐ ( 6946 lượt đánh giá )
  • Khớp với kết quả tìm kiếm: Vimentor chi tiết bài học Lớp và đối tượng trong C++

Xem thêm các bài viết khác thuộc chuyên mục: Kiến thức lập trình

Xem Thêm  Định dạng ngày trong Python - trăn định dạng ngày giờ