2012-06-28 41 views
5

Tôi đã tự hỏi rằng khi tôi tạo một thể hiện của một mẫu lớp với chỉ định tham số kiểu mẫu.
1) tại sao hàm không được gọi không được instatiated? .
2) chúng không được biên dịch cho đến khi tôi cố gắng sử dụng?
3) logic đằng sau hành vi này là gì?

Tại sao các thành viên lớp mẫu chưa được kích hoạt lại không được khởi tạo?

Ví dụ

template <class T> 
class cat{ 
public: 

T a; 
void show(){ 
    cout << a[0]; 
} 
void hello(){ 
    cout << "hello() get called \n"; 
} 
}; 

int main(){ 
cat<int> ob1; // I know that show() did not get instatiated, otherwise I will get an error since a is an int 
ob1.hello(); 

} 
+0

trình biên dịch gì bạn đã sử dụng không? –

Trả lời

3

Nếu chúng khởi tạo toàn bộ lớp, bạn có thể nhận được mã không hợp lệ.

Bạn không phải lúc nào cũng muốn điều đó.

Tại sao? Bởi vì trong C++, đó là khó khăn (và trong một số trường hợp, hoàn toàn không thể, theo như tôi biết) để nói, "chỉ biên dịch mã này nếu X, Y và Z là đúng".

Ví dụ: bạn sẽ nói như thế nào, "chỉ người tạo bản sao của tôi nếu đối tượng được nhúng có thể được sao chép"? Theo tôi biết, bạn không thể.

Vì vậy, họ chỉ khiến họ không biên dịch trừ khi bạn thực sự gọi cho họ.

+0

chỉ dành cho lớp mẫu hoặc trong bất kỳ lớp nào nói chung, và nếu tôi không sử dụng một hàm trong một khuôn mẫu lớp, điều này có nghĩa là cá thể của mẫu lớp này không chứa hàm này ở tất cả? – AlexDan

+1

@AlexDan: Chỉ các khuôn mẫu. Có lẽ, đối với các lớp thông thường, bạn đã biết mọi thứ về vì vậy, không có gì để ngăn chặn - chỉ cần không bao gồm mã không biên dịch, tuy nhiên, đối với các mẫu, bạn không biết chúng sẽ được khởi tạo bằng cách nào, nhưng bạn vẫn muốn có khả năng viết mã bình thường - vì vậy trình biên dịch sẽ giúp bạn thích cái này – Mehrdad

+0

do đó bằng cách thực hiện 'cat ob1;' Im chỉ tạo thành viên biến và không phải của các thành viên chức năng là một thành viên của đối tượng ob1 yet.if này là chính xác, sau đó không trình biên dịch để lại một số bộ nhớ bên trong ob1 đối tượng trong trường hợp tôi gọi một chức năng? và cũng thay đổi kích thước ob1 trước và sau khi tôi gọi một chức năng mới? cảm ơn rất nhiều . – AlexDan

2

Không có mã được tạo ra cho cat<int>::show() bởi vì bạn không bao giờ gọi nó. Nếu bạn đã gọi nó, bạn sẽ nhận được một lỗi biên dịch. Các hàm mẫu không bao giờ được gọi là không tồn tại.

Mẫu nhỏ hơn cơ chế thay thế thử nghiệm. Điều này làm cho chúng rất mạnh mẽ. Bạn, với tư cách là lập trình viên, có thể muốn tạo một số cat<int> khi biết rằng bạn sẽ không bao giờ gọi show() hoặc gọi bất kỳ thứ gì khác không hợp lệ. Trình biên dịch cho bạn biết nếu bạn đã làm, do đó, nó hoạt động ra độc đáo.

Vì vậy, nếu câu hỏi của bạn là "tại sao nó hoạt động theo cách này", tôi sẽ hỏi bạn "tại sao không"? Đó là một lựa chọn thiết kế. Lựa chọn này cho phép tôi sử dụng một loại mẫu một cách an toàn và vẫn được hưởng lợi từ các phần khác của mã. Có hại gì? Bạn cũng tạo ra ít mã, đó là một điều tốt, phải không?

+1

Tôi khá chắc chắn OP đã biết điều này. Câu hỏi rõ ràng nói "tại sao". – Mehrdad

+0

@Mehrdad: Tôi đã thêm một chút ngay bây giờ trước khi tôi nhìn thấy nhận xét của bạn. Tôi cho rằng tôi không hiểu; "tại sao"? Tại sao không? Nó an toàn và cho phép tôi làm nhiều hơn với tư cách là một lập trình viên, vậy tại sao lại hạn chế sử dụng các mẫu? –

+0

@Mehrdad: Câu trả lời cho bất kỳ "Tại sao?" câu hỏi trong thiết kế ngôn ngữ là "Bởi vì các nhà thiết kế đã quyết định như vậy." Lựa chọn khó khăn phải được thực hiện trong thiết kế, và thường không có lý do rõ ràng rõ ràng lý do tại sao họ đã đi theo cách này hay cách khác. – abelenky

6

Mẫu không phải là mã - chúng là mẫu được sử dụng để tạo mã thực. Mẫu không hoàn thành cho đến khi bạn cung cấp các tham số để mã không thể được thực hiện trước thời hạn. Nếu bạn không gọi hàm với một tập hợp các tham số mẫu cụ thể, mã sẽ không bao giờ được tạo.

+0

Đồng ý +1, trực tiếp và cho điểm. –

+1

Không đúng 100%, chỉ cho các cảnh báo ngầm. Trong các khuôn mẫu rõ ràng tất cả các hàm được tạo ra (có nghĩa là nó là một quyết định thiết kế không phải lúc nào cũng làm, và chỉ trả lời đúng một nửa: nó lặp lại câu hỏi mà không cung cấp nhiều lời giải thích) –

3

Để tôn tạo nhiều hơn một chút: đây thường được gọi là duck typing, và mấu chốt là nó cho phép bạn viết "mô hình lớp học" trong đó một số hàm thành viên có thể áp dụng khi khởi tạo với một mẫu loại, khác các thành viên có thể áp dụng khi khởi tạo với một kiểu mẫu thứ hai, và chỉ yêu cầu những cái bạn thực sự gọi để biên dịch, bạn có thể viết ít mã hơn nhiều cho các hoạt động mà trở nên phổ biến.

Bằng cách không yêu cầu tất cả các chức năng thành viên được biên dịch, bạn sẽ nhận được tất cả các tính năng kiểm tra kiểu tĩnh trên các hàm thực sự được biên dịch.

Ví dụ, hãy tưởng tượng bạn có:

template <typename E> 
    class myContainer { 

     // Imagine that constructors, setup functions, etc. were here 

     void sort(); // this function might make sense only if E has an operator< defined 

     E max(); // compute the max element, again only makes sense with a operator< 

     E getElement(int i); // return the ith element 

     E transmogrify(); // perhaps this operation only makes sense on vectors 
    }; 

Sau đó, bạn có

// sort() and getElement() makes total sense on this, but not transmogrify() 
    myContainer<int> mci;   

    // sort and max might not be needed, but getElement() and transmogrify() might 
    myContainer<vector<double>> mcvd;   
+0

tôi downvoted mọi câu trả lời và upvoted cái này. cuối cùng một trong đó không tuyên bố rằng một thành viên nontemplate chức năng là một mẫu –

+0

@ JohannesSchaub-litb: nếu chức năng thành viên nontemplate không phải là một mẫu. sau đó làm thế nào đến nó không được instatiated cho đến khi tôi sử dụng nó? – AlexDan

+1

@alexdan Điều này được giải thích trong câu trả lời i upvoted –

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