2011-07-22 35 views
15

Tôi là một lập trình viên C++ mới, nhưng tôi nghĩ tôi biết đủ về C++ cho đến hôm nay khi tôi bắt gặp mã như thế này tại nơi làm việc và không hiểu nó hoạt động như thế nào .Mẫu C++ Crazy - Một mẫu để truy cập các thuộc tính riêng lẻ của một lớp

class Object 
{ 
}; 

template < 
     class PropObject, 
     class PropType, 
     PropType PropObject::* Prop 
     > 
class PropReader 
{ 
public: 
    void print(Object& o) 
    { 
     PropObject& po = static_cast<PropObject &>(o); 
     PropType& t = po.*Prop; 

     cout << t << "\n"; 
    } 
}; 

class Student : public Object 
{ 
public: 
    int age; 
    int grade; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Student s; 
    s.age = 10; 
    s.grade = 5; 

    PropReader<Student, int, &Student::age> r; 
    PropReader<Student, int, &Student::grade> r2; 

    r.print(s); 
    r2.print(s); 
} 

Tôi nghĩ rằng tôi đã hiểu ở mức cao. Nhưng điều này cụ thể PropType PropObject::* Prop trong tuyên bố mẫu phiền tôi. Nó có nghĩa là gì? Tôi đang tìm kiếm một lời giải thích từ các chuyên gia C++. Tôi muốn hiểu nó, để tôi có thể sử dụng nó tốt hơn. Nó trông rất hữu ích mặc dù.

Trả lời

18

Mẫu C++ nổi tiếng với việc lấy các loại làm đối số, nhưng chúng cũng có thể được tham số hóa trên các loại dữ liệu khác. Ví dụ, bạn có thể templatize một lớp trên một số nguyên, như thể hiện ở đây:

template <typename T, unsigned int N> class Array { 
private: 
    T array[N]; 

public: 
    /* ... */ 
}; 

Templates cũng có thể được tham số qua con trỏ, miễn là con trỏ đáp ứng tiêu chí nhất định (ví dụ, nó có để đánh giá đến một địa chỉ của một cái gì đó có thể được xác định tại thời gian biên dịch).Ví dụ, đây là hoàn toàn hợp pháp:

template <int* Pointer> class ThisIsLegal { 
public: 
    void doSomething() { 
     *Pointer = 137; 
    } 
}; 

Trong code của bạn, các mẫu được tham số hóa hơn một con trỏ-to-đẳng cấp thành viên. Một thành viên lớp-con trỏ tương tự như một con trỏ ở chỗ nó gián tiếp đề cập đến một số đối tượng. Tuy nhiên, thay vì trỏ đến một đối tượng, thay vào đó nó trỏ đến một trường trong một lớp. Ý tưởng là bạn có thể dereference một con trỏ-to-class-thành viên liên quan đến một số đối tượng để chọn lĩnh vực đó ra khỏi lớp. Dưới đây là một ví dụ đơn giản của con trỏ-to-class thành viên:

struct MyStruct { 
    int x, y; 
}; 

int main() { 
    MyStruct ms; 
    ms.x = 137; 
    ms.y = 42; 

    int MyStruct::* ptr; // Declare a pointer to a class member. 
    ptr = &MyStruct::x; // Now points to the field 'x' 

    ms.*ptr = 0;   // Set the 'x' field of ms to be zero. 
} 

ý rằng cú pháp cho tuyên bố một con trỏ-to-đẳng cấp thành viên là

Type ContainingClass::* pointerName; 

Vì vậy, trong đoạn mã trên, int MyStruct::* ptr phương tiện . "một con trỏ đến một int bên trong một MyStruct lớp

trong mã mà bạn đã đăng, tờ khai mẫu lần đọc như thế này:

template < 
    class PropObject, 
    class PropType, 
    PropType PropObject::* Prop 
    > 
class PropReader 

Hãy xem ý nghĩa của điều này. Đối tượng đầu tiên hai đối số mẫu có thuộc tính sẽ được đọc và PropType, loại thuộc tính đó. "Đối số cuối cùng cho mẫu là một thành viên lớp con trỏ có tên là Prop trỏ vào bên trong một PropObject tại một trường gõ PropType Ví dụ, bạn có thể nhanh chóng mẫu này với MyStruct như thế này:.

PropReader<MyStruct, int, &MyStruct::x> myPropReader; 

Bây giờ, chúng ta hãy xem những gì còn lại của mã không phần nội dung của lớp mẫu này được in lại ở đây:.

void print(Object& o) 
{ 
    PropObject& po = static_cast<PropObject &>(o); 
    PropType& t = po.*Prop; 

    cout << t << "\n"; 
} 

Một số điều này có thể được đọc khá dễ dàng. eter để chức năng này là một tham chiếu đến một Object có tên o, và dòng cuối cùng in ra một số lĩnh vực. Hai dòng này là rất phức tạp:

PropObject& po = static_cast<PropObject &>(o); 
PropType& t = po.*Prop; 

dòng đầu tiên này là một thợ đúc chư nói rằng "cố gắng đúc lập luận o đến một tài liệu tham khảo của loại PropObject Ý tưởng, tôi đoán, là Object là một số lớp cơ sở. Tham số cho hàm chỉ là một đơn giản Object, và dàn diễn viên này cố gắng chuyển đổi nó thành một cái gì đó của loại thích hợp (nhớ rằng PropObject là đối số mẫu cho biết loại đối tượng là gì). điều này sử dụng static_cast, nếu chuyển đổi không được xác định (ví dụ: bạn đã cố gắng tạo mẫu trên int hoặc vector<string>), mã sẽ không biên dịch. e, mã tin tưởng rằng dàn diễn viên là an toàn, sau đó nhận được một tham chiếu của loại PropObject đến tham số tham chiếu.

Cuối cùng, dòng cuối cùng là

PropType& t = po.*Prop; 

này sử dụng cú pháp dereference con trỏ-to-lớp-viên tôi đã đề cập trước đó để nói "chọn lĩnh vực được trỏ tới bởi Prop (mẫu tham số), sau đó cửa hàng một tham chiếu đến nó có tên là t.

Vì vậy, trong ngắn hạn, các mẫu

  1. yêu cầu bạn cho các loại của một số đối tượng.
  2. Yêu cầu bạn nhập loại trường nào đó trong đối tượng đó.
  3. Yêu cầu bạn trỏ đến trường trong đối tượng đó.
  4. Cung cấp chức năng print cho một đối tượng cố gắng in ra trường đó.

Whew! Đó là khó khăn! Hi vọng điêu nay co ich!

+1

Đó là một câu trả lời tuyệt vời templatetypedef .. không có thắc mắc bạn có tên người dùng đó :) – cgcoder

3

PropObject::* là một con trỏ thành viên (thành viên dữ liệu, trong trường hợp này). Về cơ bản, nó là con trỏ tới thành viên (không tĩnh) (là Student::ageStudent::grade trong trường hợp mã của bạn).

Để sử dụng, bạn phải chỉ định đối tượng this mà chức năng sẽ sử dụng. Điều đó được thực hiện bằng cách sử dụng toán tử .* hoặc ->*; trong trường hợp này, dòng PropType& t = po.*Prop; xử lý điều đó, trong đó po được sử dụng làm đối tượng this cho các thành viên.

1

Đó là cú pháp để chuyển con trỏ đến một thành viên làm đối số. Cụ thể trong trường hợp này, các thành viên có thể được thông qua agegrade. Trong khi mẫu args đang chỉ định lớp Student, đó là thành viên và thuộc tính thành viên là int.

Nếu bạn thêm một tên chuỗi để sinh viên tuyên bố PropReader có thể trông như thế này:

PropReader<Student, std::string, &Student::name> r3; 
0

Nhưng đặc biệt PropType PropObject :: * Prop này trong mẫu khai làm tôi bực mình. Nó có nghĩa là gì?

PropType PropObject::* Prop 

này định nghĩa con trỏ mà chỉ một biến thành viên của một lớp, trong trường hợp đặc biệt này, đó là lớp PropObject và loại biến là PropType.

4

khai báo trong C hoặc C++ thường tốt nhất đọc từ phải sang trái:

PropType PropObject::* Prop 
         ~~~~ The Prop template parameter 
        ~~~  is a pointer to a member 
     ~~~~~~~~~~   of a PropObject 
~~~~~~~~      where that member has type PropType 

Điều này có thể được nhìn thấy trong hành động trong sự khởi tạo:

PropReader<Student, int, &Student::age> r; 

Đây là mẫu tham số thứ ba là một con trỏ cho một thành viên của lớp Student, có loại int.

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