2016-10-03 16 views
6

Tôi nhầm lẫn về cách CRTP được biên dịch. Nếu chúng tôi có một cái gì đó như thế này:Tại sao CRTP không gây ra tổ chức vô hạn?

template<class T> 
class Base 
{ 

}; 
class Derived : public Base<Derived> 
{ 

}; 

Tại sao điều gì đó không giống với điều này xảy ra trong quá trình biên dịch?

(X[Y] biểu thị X thừa hưởng từ Y)

Sau khi khai báo một trường hợp Derived Derived d;

d đang được mở rộng thành một tái phát vô hạn của các mẫu và thừa kế

d[Base<Derived[Base<Derived[Base<Derived[Base<Derived[...]>]>]>]>]

Tại sao điều này có xảy ra không? Tất cả các hướng dẫn trên CRTP chỉ giải thích những gì bạn có thể làm với nó, không phải những gì xảy ra dưới mui xe (ít nhất là mơ hồ).

+0

Trong ngữ cảnh 'Cơ sở',' T' không phải là loại hoàn chỉnh. Bởi vì điều này, bạn không thể truy cập vào những thứ như 'typedef' được định nghĩa trong' T' từ 'Base' (xem [1] (http://stackoverflow.com/questions/6006614/c-static-polymorphism-crtp- và-sử dụng-typedefs-từ-nguồn gốc-lớp học) và [2] (http://stackoverflow.com/questions/652155/invalid-use-of-incomplete-type)). Vì 'T' không phải là một kiểu hoàn toàn đầy đủ, trình biên dịch không phải truy cập vô hạn trong tình huống này. Ít nhất đó là sự hiểu biết của tôi. – Cornstalks

+0

@ Eichhörnchen Bởi vì tôi xuất phát từ Base, được tạo mẫu bởi Derived, được thừa hưởng từ Base, được tạo mẫu bởi Derived, được thừa kế từ Base ... –

+0

@Cornstalks yea âm thanh về đúng –

Trả lời

7

Các khái niệm cơ bản để hiểu là một thể hiện của một mẫu chỉ là một lớp. Về cơ bản nó không khác gì so với bất kỳ lớp nào khác.

Khi bạn có một định nghĩa mẫu tiêu biểu:

template<typename T> class Base; 

Sau đó mẫu Ví dụ:

Base<int> 

là chỉ là một lớp của tên đó. Nó không liên quan gì đến int, và hoàn toàn không có mối quan hệ nào, với một số int. Nó không kế thừa từ nó, theo một cách nào đó, hoặc bằng bất kỳ cách nào.

Bước tiếp theo:

class Derived; 

template<typename T> class Base {}; 

Base<Derived> foo; 

Một lần nữa, Base<Derived> chỉ là một lớp. Nó không có mối quan hệ nội tại với Derived. Nó không xuất phát từ nó, không thừa kế từ nó, không có gì.

Vì vậy, bây giờ chúng ta thực hiện bước cuối cùng:

template<class T> 
class Base 
{ 

}; 

class Derived : public Base<Derived> 
{ 

}; 

này khai báo một lớp được gọi là Derived, mà kế thừa từ một lớp được gọi là Base<Derived>. Và Base<Derived> chỉ là một lớp học. Đó là một lớp rất đơn giản. Không thể đơn giản hơn thế. Nó không có bất kỳ phương pháp nào. Nó không có bất kỳ thành viên nào. Không riêng tư, được bảo vệ hoặc công khai. Đó là một lớp học nhỏ, nhưng nó có các quyền và đặc quyền giống như bất kỳ lớp nào khác. Bạn có thể khai báo một con trỏ đến nó. Hoặc một tham chiếu đến nó. Nó chỉ là một lớp.

Một lần nữa, khái niệm chính là một thể hiện của một mẫu chỉ là một lớp. Nó không "kế thừa" trong bất kỳ cách nào từ lớp đó là tham số cho mẫu. Trong trường hợp này, cá thể mẫu hoàn toàn trống rỗng, nhưng nó có thể làm bất cứ điều gì mà bất kỳ lớp nào khác có thể làm. Nó có thể có các thành viên công cộng, riêng tư và được bảo vệ. Nó có thể xuất phát từ một số lớp khác, có thể là một cá thể mẫu khác (vì một cá thể mẫu chỉ là một lớp). Hoặc, một số lớp khác có thể lấy được từ cá thể mẫu, vì một cá thể mẫu chỉ là một lớp.

Không có tổ ấm vô hạn nào tại đây. Bạn chỉ có một lớp kế thừa từ một lớp khác. Lớp thứ hai xảy ra là một cá thể mẫu, nhưng tôi có đề cập đến một cá thể mẫu chỉ là một lớp không?

3

Giải thích đơn giản: bởi vì sau đây là hoàn toàn hợp lệ:

template<class T> 
class Base 
{ 
}; 

class Derived /* at this point, Derived is declared (not defined) */; 

int main() 
{ 
    Base<Derived> base; // the definition of Derived (or lack thereof) is irrelevant. 
} 
Các vấn đề liên quan