2013-04-10 16 views
9

Hãy xem xét các lớp Qt sau:Tại sao Qt sử dụng d_func() để khởi tạo một con trỏ tới dữ liệu cá nhân?

#include <QScopedPointer> 

class MyClassPrivate; 
class MyClass 
{ 
    public: 
     MyClass(); 
     ~MyClass(); 
    private: 
     QScopedPointer<MyClassPrivate> d_ptr; 
     Q_DECLARE_PRIVATE(MyClass) 
} 

Lớp này tương tự như cấu trúc của hầu hết các lớp học Qt mà thực hiện thực hiện tư nhân. Vĩ mô Q_DECLARE_PRIVATE sẽ gây ra sự mở rộng sau (như của Qt5):

inline MyClassPrivate* d_func() 
    { return reinterpret_cast<MyClassPrivate *>(qGetPtrHelper(d_ptr)); } 
inline const MyClassPrivate* d_func() const 
    { return reinterpret_cast<const MyClassPrivate *>(qGetPtrHelper(d_ptr)); } 
friend class MyClassPrivate; 

Đây là khó hiểu - tại sao không d_ptr được sử dụng trực tiếp trong các chức năng thành viên? Nói cách khác, thay vì làm điều này:

Q_D(MyClass); 
d->member = 12345; 

Tại sao không làm điều này?

d_ptr->member = 12345; 

lý do có một chức năng rõ ràng rằng (về cơ bản) chỉ trả về d_ptr và gánh chịu những phí của một biến thêm trên stack là gì?

Trả lời

7

Nếu lớp dẫn xuất và lớp cơ sở có cấu trúc riêng, nó sẽ lãng phí nhiều bộ nhớ hơn, do đó trong Qt, lớp riêng cũng được thừa hưởng và lớp dẫn xuất và lớp cơ sở chia sẻ một d_ptr. Vấn đề làm như vậy là d_ptr giờ là kiểu BasePrivate.

class Base 
{ 
protected: 
    BasePrivate * d_ptr; 
} 

class Derived 
{ 
// There is not d_ptr declared 
} 

Vì vậy, bạn có thể thấy, trong lớp dẫn xuất, khi truy cập d_ptr, loại này là BasePrivate *. Vì vậy, nó cần phải cast d_ptr để DerivedPrivate *. Hàm d_func là inline, một khi được biên dịch, nó sẽ luôn cast d_ptr vào đúng kiểu.

This post minh họa tốt hơn những gì tôi nói ở đây, tôi khuyên bạn nên đọc nó.

+0

Nếu không có lớp nào của tôi kế thừa từ nhau, có lợi thế nào khi sử dụng macro 'Q_DECLARE_PRIVATE' không? Là thừa kế lý do duy nhất cho các phương pháp nội tuyến? –

+1

@NathanOsman Tôi nghĩ rằng không nên có lý do để sử dụng macro nếu bạn đang sử dụng hai lớp không kế thừa lẫn nhau. Mỗi người trong số họ có thể có một triển khai cá nhân. Nhưng thực tế là trong Qt, hầu như tất cả các lớp được thừa kế từ lớp QObject, và thừa kế có thể rất sâu đôi khi, nếu không có cơ chế như vậy, nó sẽ phải chịu một chi phí lớn cho bộ nhớ. –

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