2013-03-22 27 views
8

Tôi đang thử nghiệm với C++ để hiểu cách lớp/cấu trúc và đối tượng tương ứng của chúng được đặt trong bộ nhớ và tôi hiểu rằng mỗi trường của một lớp/cấu trúc là một phần bù vào đối tượng tương ứng của chúng.).Các chức năng thành viên được lưu trữ cho một đối tượng ở đâu?

Tôi không hiểu tại sao, ngay cả khi tôi có thể có con trỏ hàm thành viên, các mã sau đây không làm việc:

struct mystruct 
{ 
    void function() 
    { 
     cout << "hello world"; 
    } 
    int c; 
}; 

int main() 
{ 
    unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c); 
    unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); // ERROR - error C2276: '&' : illegal operation on bound member function expression 



    return 0; 
} 

Câu hỏi của tôi là: tại sao các dòng

unsigned int offset_from_start_structure = (unsigned int)(&((mystruct*)0)->c); 

biên dịch và trả lại cho tôi khoản bù của trường "c" từ đầu cấu trúc và dòng

unsigned int offset_from_start_structure2 = (unsigned int)(&((mystruct*)0)->function); 

d thậm chí không biên dịch?

+5

Chức năng thành viên không được lưu trữ trong các đối tượng (tại sao chúng? Chúng giống nhau cho tất cả các đối tượng thuộc loại đó). Và nếu nó giúp (có thể không, có lẽ nó chỉ thêm nhầm lẫn nhưng tôi sẽ cố gắng anyway) con trỏ chức năng thành viên là * không * con trỏ. –

+0

Bạn mong đợi nội dung của hàm _function_ trong bộ nhớ? Các hàm không phải là dữ liệu. Họ là mã. –

+1

"Tôi đang thử nghiệm với C++ để hiểu cách lớp/cấu trúc và các đối tượng tương ứng của chúng được đặt trong bộ nhớ" chi tiết triển khai ", không có gì với ngôn ngữ –

Trả lời

15

Các hàm thành viên hoặc gợi ý cho họ không được lưu trữ trong đối tượng. (virtual chức năng thường được gọi thông qua một con trỏ được lưu trữ trong một bảng mà một đối tượng có một con trỏ duy nhất để) Đây sẽ là một lớn lãng phí bộ nhớ. Chúng thường được lưu trữ trong một phần bộ nhớ mã, và được biết đến với trình biên dịch. Đối tượng (*this) thường được chuyển thành một tham số ẩn để các chức năng biết đối tượng nào hoạt động khi chúng được gọi.

Vì vậy, trong điều kiện của giáo, bạn phải

0x10001000 void A::foo 
.......... {code for A::foo} 

push a; 
call A::foo (0x10001000) 
pop a; 

nơi a là đối tượng bạn đang gọi điện thoại foo trên.

+0

Cảm ơn bạn đã làm rõ nhưng tại sao dây chuyền không hoạt động? Nó phải trả lại một địa chỉ cố định ít nhất –

+0

@JohnnyPauling không, nó không nên. Các '& ((mystruct *) 0) -> c' là hành vi không xác định, bạn không thể chỉ dereference một con trỏ null. Google cho 'con trỏ đến hàm thành viên' và bạn sẽ tìm thấy cách thích hợp để thực hiện nó. –

+0

Tôi không nghĩ đó là hành vi không xác định, nó trả về giá trị bù của trường c mỗi khi tôi gọi nó và nó hoạt động cho các trường liên tiếp khác nên tôi đã tự hỏi tại sao nó không hoạt động với hàm –

2

Con trỏ chức năng thành viên trong thực tế không được lưu trữ trong các đối tượng: không cần thiết. Tiêu chuẩn C++ không chỉ định chính xác cách thực hiện các hàm ảo sẽ được thực hiện, nhưng thực hành chung cho các hàm thành viên ảo là mỗi đối tượng chứa một con trỏ tới một bảng các con trỏ hàm; con trỏ này được gọi là vtable pointer.

Bạn có thể cố gắng giữ lại “Inside the C++ object model” bởi Stanley Lippman. Hoặc, bạn chỉ có thể cố gắng giữ lại pointers tutorial cũ của tôi, một lần được tham chiếu từ bài viết của Wikipedia, trước khi trang chủ sau đó của tôi biến mất.


Về câu hỏi thứ hai, tại sao lấy địa chỉ của p->memberFunc làm cho trình biên dịch nghẹt thở một chút, cũng biểu hiện mà không có loại, nó chỉ là một cú pháp tổ chức , mà bạn có thể áp dụng một danh sách đối số để theo thứ tự để gọi hàm.

Để wit,

struct S 
{ 
    void foo() {} 
}; 

#include <iostream> 
#include <typeinfo> 
using namespace std; 
int main() 
{ 
    S* p = 0; 
    typeid(&p->foo); 
} 

Compilation:

 
[W:\dev\test] 
>g++ foo.cpp 
foo.cpp: In function 'int main()': 
foo.cpp:12:17: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say '&S::foo' [-fpermissive] 
foo.cpp:12:22: warning: value computed is not used [-Wunused-value] 
foo.cpp:12:22: warning: statement has no effect [-Wunused-value] 

[W:\dev\test] 
> _ 
Các vấn đề liên quan