2013-04-17 56 views
9

Hãy nói rằng chúng tôi có một lớp MộtVề sizeof của một hàm thành viên lớp con trỏ

class A; 

và những typedefs

typedef void (A::*a_func_ptr)(void); 
typedef void (*func_ptr)(void); 

Câu hỏi của tôi là lý do tại sao sizeof (a_func_ptr) trả về 16, trong khi sizeof (func_ptr) trả về 4 (như đối với bất kỳ con trỏ nào trên hệ thống x86)?

Ví dụ

int main(int argc, char *argv[]) 
{ 
    int a = sizeof(a_func_ptr); 
    int b = sizeof(func_ptr); 
} 
+5

Đó là [vì điều này] (http://stackoverflow.com/a/13875868/335858). – dasblinkenlight

Trả lời

8

Câu hỏi của tôi là lý do tại sao sizeof (a_func_ptr) trả về 16, trong khi sizeof (func_ptr) trả về 4 (như đối với bất kỳ con trỏ trên hệ thống x86)?

Vì con trỏ đến thành viên được triển khai khác nhau. Chúng là không phải con trỏ dưới mui xe. Một số trình biên dịch, chẳng hạn như MSVC, triển khai chúng dưới dạng struct với nhiều thành viên trong đó.

Đọc bài viết thú vị này:

Lưu ý rằng trong một số trình biên dịch, họ có thể có cùng một kích thước. Điểm mấu chốt là: chúng phụ thuộc vào trình biên dịch.

1

Hàm con trỏ thành viên của lớp không giữ "địa chỉ chính xác" như con trỏ thông thường. Nó lưu trữ nhiều thông tin hơn con trỏ hàm thông thường.

Vì vậy, khi bạn sử dụng sizeof để đo kích thước của hàm trỏ đến thành viên của một lớp, bạn không nên mong đợi rằng nó sẽ có cùng kích thước với con trỏ hàm thông thường.

+0

Một phương pháp, trái với một thành viên dữ liệu, được chia sẻ bởi tất cả các trường hợp của lớp để nó không thể có một bù đắp trong bố cục lớp. Hay bạn có nghĩa là con trỏ tới thành viên cũng phải lưu trữ, ít nhất, con trỏ 'this' này ngoài địa chỉ của phương thức? – syam

+0

@syam những gì tôi đã cố gắng để nói rằng con trỏ đến chức năng thành viên lưu trữ thông tin nhiều hơn con trỏ chức năng thường xuyên. Phần tưởng tượng đó có thể gây hiểu lầm, tôi sẽ loại bỏ nó. – taocp

0

Mặc dù con trỏ hàm trong C và C++ có thể được thực hiện như địa chỉ đơn giản, do đó thường sizeof (Fx) == sizeof (void *), thành viên con trỏ trong C++ thường được thực hiện như "con trỏ chất béo", thường là hai hoặc ba lần kích thước của một con trỏ hàm đơn giản, để xử lý với thừa kế ảo.

Nguồn: Wikipedia

SO answer offers additional information này.

1

xem xét như sau:

#include <iostream> 

class A { 
public: 
    virtual void foo(){ std::cout << "A::foo" << std::endl; } 
    void bar(){ std::cout << "A::bar" << std::endl; } 
}; 

class B : public A { 
public: 
    void foo(){ std::cout << "B::foo" << std::endl; } 
    void bar(){ std::cout << "B::bar" << std::endl; } 
}; 

int main() { 
    a_func_ptr f = &A::foo; 
    a_func_ptr g = &A::bar; 
    B b; 
    A a; 
    (b.*f)(); 
    (b.*g)(); 
    (a.*f)(); 
    (a.*g)(); 
} 

Output:

B::foo 
A::bar 
A::foo 
A::bar 

Cả hai con trỏ thành viên là cùng loại, nhưng cả hai chuyển một cách chính xác các cuộc gọi trong mọi trường hợp.

Bằng cách nào đó, chương trình được tạo ra phải biết khi một con trỏ đến phương pháp thực sự là một phương pháp đơn giản hoặc một ảo một. Do đó, biểu diễn thời gian chạy của một con trỏ phương thức phải bao gồm nhiều thông tin hơn để xử lý trường hợp thứ hai.

Lưu ý: kích thước dường như phụ thuộc vào việc triển khai (tôi nhận được 8 trên hệ thống của mình).

+0

không có bí danh của "a_func_ptr" - tại sao bạn vượt qua mã không hoạt động? – rikimaru2013

Các vấn đề liên quan