Ngôn ngữ C++ cung cấp các hàm virtual
. Trong các ràng buộc của việc thực hiện ngôn ngữ C thuần túy, làm thế nào để đạt được hiệu quả tương tự?Làm cách nào có thể triển khai các hàm ảo C++ trong C
Trả lời
bị đánh cắp từ here.
Từ lớp C++ đoạn mã
class A {
protected:
int a;
public:
A() {a = 10;}
virtual void update() {a++;}
int access() {update(); return a;}
};
một C có thể được bắt nguồn. Ba hàm thành viên C++ của class A
được viết lại bằng cách sử dụng mã out-of-line (độc lập) và được thu thập theo địa chỉ vào một cấu trúc có tên là A_functable
. Các thành viên dữ liệu của A
và kết hợp với bảng chức năng vào một cấu trúc C có tên là A
.
struct A;
typedef struct {
void (*A)(struct A*);
void (*update)(struct A*);
int (*access)(struct A*);
} A_functable;
typedef struct A{
int a;
A_functable *vmt;
} A;
void A_A(A *this);
void A_update(A* this);
int A_access(A* this);
A_functable A_vmt = {A_A, A_update, A_access};
void A_A(A *this) {this->vmt = &A_vmt; this->a = 10;}
void A_update(A* this) {this->a++;}
int A_access(A* this) {this->vmt->update(this); return this->a;}
/*
class B: public A {
public:
void update() {a--;}
};
*/
struct B;
typedef struct {
void (*B)(struct B*);
void (*update)(struct B*);
int (*access)(struct A*);
} B_functable;
typedef struct B {
A inherited;
} B;
void B_B(B *this);
void B_update(B* this);
B_functable B_vmt = {B_B, B_update, A_access};
void B_B(B *this) {A_A(this); this->inherited.vmt = &B_vmt; }
void B_update(B* this) {this->inherited.a--;}
int B_access(B* this) {this->inherited.vmt->update(this); return this->inherited.a;}
int main() {
A x;
B y;
A_A(&x);
B_B(&y);
printf("%d\n", x.vmt->access(&x));
printf("%d\n", y.inherited.vmt->access(&y));
}
Phức tạp hơn cần thiết, nhưng nó được điểm qua.
+1 Ví dụ tuyệt vời: đây là khoảng gần như bạn có thể nhận được dịch vtables để C và là xa hơn thanh lịch hơn C lập trình làm những việc như hàm con trỏ phôi hoặc đúc cấu trúc của con trỏ chức năng. Nó vẫn cồng kềnh và vụng về, nhưng hey, C không được thiết kế cho việc này. – stinky472
@ stinky472: Tôi đồng ý với bạn, nhưng khi ai đó đang ở thời điểm cần mã như thế thì nó không có ý nghĩa gì cả. Một số ngôn ngữ nhất định phù hợp hơn với một số vấn đề nhất định. – Alerty
Rất đúng, nhưng tôi đã bị buộc phải làm việc trong các hệ thống C cố gắng triển khai OOP. Họ đã làm điều đó bằng cách đúc các cấu trúc với con trỏ hàm (như casting struct A), thay vì chỉ truyền A cho đa hình và cho phép mọi cấu trúc giống lớp con chỉ lưu trữ A và gán các địa chỉ và dữ liệu chức năng thích hợp cho nó. Điều này, ít nhất, là thanh lịch hơn nhiều so với cấu trúc đúc hoặc đúc con trỏ chức năng. – stinky472
Here là mô tả về chức năng ảo.
Không có cách nào để thực hiện các chức năng ảo trong đồng bằng C, vì C không có khái niệm thừa kế.
Cập nhật: Như được thảo luận trong phần bình luận bên dưới, có thể làm điều gì đó tương tự như hàm ảo trong C bằng cách sử dụng cấu trúc và con trỏ hàm. Tuy nhiên, nếu bạn đã quen với một ngôn ngữ như C++ có chức năng ảo "đúng", có thể bạn sẽ tìm thấy xấp xỉ C gần như ít thanh lịch và khó sử dụng hơn.
thực sự, có một khái niệm về kế thừa trong C nhưng nó không tôn trọng kiểm soát ACCESS tại đây: http://stackoverflow.com/questions/577465/in-c-can-i-derive-a-class-from- a-struct –
@Gollum: Cấu trúc C++ không giống cấu trúc C. – Alerty
Bạn không thể thực hiện trực tiếp (lớp bị thiếu :)) - nhưng không có vấn đề gì khi triển khai hệ thống như vậy bằng cách sử dụng các cấu trúc và các con trỏ hàm. – ManniAT
Chức năng ảo là một tính năng của hướng đối tượng của C++. Chúng đề cập đến các phương thức phụ thuộc vào một cá thể đối tượng cụ thể thay vì kiểu bạn đang mang chúng xung quanh.
Nói cách khác: nếu bạn khởi tạo một đối tượng là Bar, sau đó truyền nó sang Foo, các phương thức ảo sẽ vẫn là những cái mà chúng được tạo ra (được định nghĩa trong Bar), trong khi các phương thức khác sẽ là Foo.
Chức năng ảo thường được triển khai bằng cách sử dụng vtables (đó là dành cho bạn để nghiên cứu thêm về;)).
Bạn có thể mô phỏng những thứ tương tự trong C bằng cách sử dụng cấu trúc làm đối tượng của người nghèo và lưu con trỏ hàm trong chúng.
(một cách chính xác hơn, chức năng không ảo làm cho nó mơ hồ mà lớp phương pháp này cần được thực hiện từ, nhưng trong thực tế tôi tin rằng C++ sử dụng loại hiện hành.)
@GCC .... Một hàm ảo được khai báo trong lớp cơ sở của một đối tượng và sau đó được "ghi đè" hoặc được triển khai trong các lớp con. tức là, bạn có lớp Xe cơ sở và bạn tạo hai lớp con, Xe máy và Ô tô. Lớp cơ sở sẽ khai báo một hàm ảo của AddTires() Sau đó, các lớp con sẽ thực hiện hàm này và mỗi lớp con sẽ thực hiện nó một cách khác nhau. Một chiếc xe có 4 bánh xe, nơi mà một chiếc xe máy có 2. Tôi không thể cung cấp cho bạn cú pháp cho C hoặc C++, mặc dù. Hy vọng điều này sẽ giúp
Tất nhiên, câu trả lời của tôi dựa trên C# và mô hình đối tượng đó – MikeTWebb
tại sao bạn lại muốn triển khai C++? Các chủ đề như thế này có thể dễ dàng tìm thấy trong sách và cũng có rất nhiều bài báo trực tuyến. Bằng cách đặt ra các loại câu hỏi này, danh tiếng của bạn sẽ bị ảnh hưởng và mọi người sẽ bắt đầu đưa bạn đến một mức độ nhất định. Vì vậy, làm tất cả các bạn có thể để tìm câu trả lời, và vẫn không thể hỏi :). –
Bạn đang cố gắng đạt được điều gì? – DRL
giáo viên đã đặt câu hỏi này cho chúng tôi –