2009-08-30 43 views
24

Tôi gặp sự cố khi gọi một lớp mẫu mà tôi có. Tôi đã khai báo một tên kiểu mới là Array, là một mẫu;Mẫu C++, liên kết lỗi

Trong tập tin .hpp:

template <typename T> 
class Array 
{ 
public: 
    Array(); 
}; 

Trong tập tin cpp:

template <typename T> 
Array<T>::Array() 
{ 
//Do something 
} 

Trong chính:

Array<int> arr; 

tôi nhận được lỗi Mối liên hệ: chưa được giải quyết biểu tượng bên ngoài vào ctor.

Bất kỳ ý tưởng nào?

+0

Sẽ hữu ích khi liên kết câu hỏi này với https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file nhưng không thực sự trùng lặp. OP không biết điều gì đó hoàn toàn được giả định trong câu hỏi đó. – Winter

Trả lời

47

Các hàm mẫu, bao gồm các hàm thành viên, phải được viết hoàn toàn bằng các tiêu đề. Điều này có nghĩa rằng nếu bạn có một lớp mẫu, việc thực hiện nó phải hoàn toàn trong một tiêu đề. Điều này là do trình biên dịch cần phải có quyền truy cập vào toàn bộ định nghĩa mẫu (không chỉ chữ ký) để tạo mã cho mỗi sự khởi tạo của khuôn mẫu.

+0

có nó hoạt động. Bạn có thể vui lòng thêm giải thích thêm lý do tại sao bạn cần phải xác định tất cả trong phần tiêu đề? Ngoài việc thực hiện tôi thêm tôi đã thêm tất cả trước khi "endif", phải không? –

+1

Đúng. Để có giải thích tốt về lý do tại sao, hãy xem http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12 và câu hỏi sau mà bạn đã liên kết với moonshadow. –

+7

Về mặt kỹ thuật, đó không phải là yêu cầu. Bạn có thể khởi tạo một cách rõ ràng khuôn mẫu trong một số đơn vị biên dịch và sử dụng mẫu đó ở nơi khác, nhưng điều này cần khá nhiều công việc dọn dẹp thủ công (thêm instantiations cho mỗi kiểu mới được sử dụng trong dự án). làm việc với các loại chưa biết). –

8

Đặt cả bản khai mẫu và mẫu chức năng định nghĩa trong tệp tiêu đề. Hầu hết các trình biên dịch C++ không dễ dàng hỗ trợ mô hình biên dịch riêng biệt cho các mẫu,

3

Vấn đề bạn có ở đây là bạn đã ẩn định nghĩa của hàm tạo trong tệp .cpp. Định nghĩa này áp dụng cho tất cả các loại T, bao gồm T dưới dạng int mà bạn sử dụng, nhưng thực sự không cung cấp bất kỳ định nghĩa nào vì nó vẫn chỉ là tuyên bố.
Trình liên kết không thể tìm thấy biểu tượng Array<int>::Array().

Bây giờ, bạn có thể thêm một dòng như thế này:

Array<int> arr1; 

đến cuối tập tin Array.cpp bạn và điều này làm cho trình biên dịch thuyết minh định nghĩa chính xác mà các mối liên kết được tìm kiếm. Tuy nhiên, điều này chỉ cung cấp một định nghĩa, nghĩa là Array<int> và không khác.

Giải pháp này sẽ làm việc, cho đến khi bạn cần một Array của một tham số mẫu khác nhau, nói, double, lúc này bạn sẽ cần phải thêm:

Array<double> arr2; 

đến cuối tập tin Array.cpp của bạn - bây giờ bạn có thể thấy điều này là không bền vững!

Nếu bạn cần C++ để làm việc với loại loại mà bạn có thể muốn trong tương lai, bây giờ là lúc di chuyển định nghĩa của ctor (và có lẽ tất cả các hàm thành viên khác) vào đầu trang (và xóa tệp .cpp vì nó sẽ không còn bất kỳ thứ gì trong đó).

0

Như đã đề cập ở trên, trong các mẫu trong C++, quá trình thực hiện các phương thức mới được thực hiện bởi trình biên dịch tại thời điểm biên dịch, vấn đề là cần phải biết tất cả định nghĩa của thm trong thời gian đó. ar h hoặc hpp tập tin.

1

Câu trả lời khác, chỉ biên dịch tệp .cpp của bạn (không phải chính) và kiểm tra kích thước của tệp đối tượng, sau đó tạo tệp rỗng.cpp rồi biên dịch tệp rỗng.cpp đó. cuối cùng so sánh kích thước của cả hai tệp đối tượng. Bạn sẽ thấy rằng chúng có cùng kích thước có nghĩa là tệp .cpp của bạn không có gì để biên dịch, do đó trình liên kết không thể tìm thấy bất kỳ thứ gì.