2010-04-29 18 views
10

Xem mã sau và làm rõ các nghi ngờ của tôi.Các cảnh báo mẫu rõ ràng ảnh hưởng đến những gì mà trình liên kết có thể tìm thấy?

  1. Vì ABC là mẫu, tại sao nó không hiển thị lỗi khi chúng tôi đặt định nghĩa hàm thành viên lớp ABC trong test.cpp?

  2. Nếu tôi đặt mã test.cpp trong test.h và remve 2, thì nó hoạt động tốt. Tại sao?

.

// test.h 
template <typename T> 
class ABC { 
public: 
    void foo(T&); 
    void bar(T&); 
}; 
// test.cpp 
template <typename T> 
void ABC<T>::foo(T&) {} // definition 
template <typename T> 
void ABC<T>::bar(T&) {} // definition 

template void ABC<char>::foo(char &); // 1 
template class ABC<char>;    // 2 
// main.cpp 
#include "test.h" 
int main() { 
    ABC<char> a; 
    a.foo();  // valid with 1 or 2 
    a.bar();  // link error if only 1, valid with 2 
} 
+0

Tại sao bạn hỏi? Họ là hai câu nói khá không liên quan. –

+0

@ Dennis Zickefoose: tất cả chúng ta đều là những người mới bắt đầu tại một số thời điểm – ereOn

+0

@ereOn: Có, nhưng tại sao anh ta hỏi có thể đi một chặng đường dài hướng tới việc gợi ý một cách tiếp cận đúng đắn khi trả lời câu hỏi của anh ta. –

Trả lời

13

Trong cả hai trường hợp, bạn đang thực hiện việc khởi tạo rõ ràng. Trong trường hợp thứ hai, chỉ ABC<char>::foo đang được khởi tạo, trong khi trong trường hợp đầu tiên ABC<char>::bar cũng được khởi tạo.

Một ví dụ tương tự khác có thể làm sáng tỏ ý nghĩa:

// test.h 
template <typename T> 
class ABC { 
public: 
    void foo(T&); 
    void bar(T&); 
}; 
// test.cpp 
template <typename T> 
void ABC<T>::foo(T&) {} // definition 
template <typename T> 
void ABC<T>::bar(T&) {} // definition 

template void ABC<char>::foo(char &); // 1 
template class ABC<char>;    // 2 
// main.cpp 
#include "test.h" 
int main() { 
    ABC<char> a; 
    a.foo();  // valid with 1 or 2 
    a.bar();  // link error if only 1, valid with 2 
} 

Trong ví dụ, trong main trình biên dịch không thể nhìn thấy cũng không foobar định nghĩa, vì vậy nó không thể nhanh chóng các phương pháp. Trình biên dịch, khi xử lý main.cpp sẽ chấp nhận mã trong chính sẵn sàng, vì bạn đang nói rằng ABC là một khuôn mẫu và nó có hai hàm này, và sẽ giả định rằng chúng sẽ được định nghĩa trong một số đơn vị dịch thuật khác.

Trong đơn vị dịch có chứa test.cpp, trình biên dịch đang nhìn thấy cả hai định nghĩa phương thức và cả hai phiên âm (phương thức/lớp) đều có thể được xử lý hoàn toàn. Nếu chỉ có phương thức khởi tạo ([1]), trình biên dịch sẽ chỉ tạo ra phương thức đó và sẽ để lại bar không xác định. Vì vậy, bất kỳ mã nào bao gồm test.h, các liên kết ngược với test.cpp được biên dịch và chỉ sử dụng phương thức foo sẽ biên dịch và liên kết, nhưng việc sử dụng bar sẽ không liên kết do nó không được xác định.

Tạo nhanh biểu mẫu lớp tạo ra các ký hiệu cho tất cả các phương thức thành viên và trong trường hợp đó, bất kỳ đơn vị dịch nào bao gồm test.h và liên kết ngược với tệp đối tượng test.cpp đã biên dịch sẽ biên dịch và liên kết.

+0

tôi có hai nghi ngờ 1. vì ABC là mẫu lý do tại sao nó không hiển thị lỗi khi chúng tôi đặt defination của chức năng thành viên lớp ABC trong test.cpp 2.if tôi đặt mã test.cpp trong test.h và loại bỏ 2 sau đó nó làm việc bạn có thể giải thích được – Suri

+0

Các định nghĩa phương thức mẫu không cần phải nằm trong nội dung lớp, ngay cả khi được đề xuất. Như với các hàm thông thường, nếu trình biên dịch chỉ thấy khai báo phương thức, nó sẽ giả định rằng nó được định nghĩa ở một nơi khác, như trong ví dụ trong cpp. Cách tiếp cận này có vấn đề ở chỗ bạn đang giới hạn các kiểu có thể được sử dụng với mẫu của bạn cho các kiểu mà bạn cung cấp một chuyên môn rõ ràng. Điều này có thể được sử dụng để tăng tốc thời gian biên dịch cho mã được tạo khuôn mẫu nặng nề mà tất cả các loại sẽ khởi tạo mẫu được biết trước. –

+0

Về câu hỏi thứ hai, nếu bạn đẩy tất cả các mã lại với nhau, trình biên dịch sẽ thấy định nghĩa mẫu (phương thức), vì vậy khi bạn gọi phương thức 'bar' trong chính nó sẽ thực hiện một sự khởi tạo ngầm của phương thức đó. Lưu ý rằng sự khởi tạo rõ ràng chỉ bắt buộc nếu trình biên dịch không thể khởi tạo nhanh mẫu, và trong hầu hết các trường hợp nếu trình biên dịch có đủ thông tin, bằng cách cho phép nó quyết định phương thức nào để khởi tạo (chỉ những người được sử dụng), bạn sẽ cải thiện thời gian biên dịch (và trung gian) các tệp đối tượng, ngay cả khi trong hầu hết các trường hợp, trình liên kết có thể loại bỏ các biểu tượng không sử dụng) –

0

(Đây là phiên bản chỉnh sửa của câu trả lời ban đầu của tôi, nhắc nhở bằng cách quan sát David Rodriguez.)

#1 instantiates lớp mẫu, và như một phần của mà instantiates tất cả các phương thức của nó.

#2 instantiates một phương thức thành viên của lớp học. Là một phần của nó, nó phải khởi tạo mẫu lớp, nhưng không phải tất cả các phương thức khác của nó.

Có thể thấy sự khác biệt nếu bạn giới thiệu lỗi phụ thuộc loại vào thanh() (ví dụ: tuyên bố như void *x = b;). Bạn sẽ gặp phải lỗi trình biên dịch với #1 nhưng không phải với #2. Cũng lưu ý rằng trình biên dịch (gcc ít nhất) sẽ không biên dịch #1 theo sau bởi #2, nhưng sẽ biên dịch một trong hai trường hợp không có trình duyệt khác hoặc nếu #2 được theo sau bởi #1.

+0

Khi khởi tạo các mẫu lớp, chỉ các thành viên thực sự _used_ được khởi tạo. Đó là lý do tại sao tôi tin rằng bạn # 2 là sai. Câu trả lời của David cũng nói như vậy. – sbi

0

Tôi đoán bạn muốn có {} thay vì; trong 1.

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