2009-03-13 5 views
15

Tôi gặp vấn đề tôi thực sự không hiểu. Tôi có một nút Node.lớp C++ với mẫu không thể tìm thấy hàm tạo của nó

template<class T> 
class node { 
protected: 
    T _data; 
public: 
    node(T data); 
}; 

Đây là tệp "node.h". Trong tập tin "node.cpp", có constructor này:

#include "node.h" 

template<class T> 
node<T>::node (T data) { 
    _data = data; 
} 

Trong khi trình biên dịch thấy không có lỗi, mối liên kết (ld) nói với tôi:

/usr/bin/ld: những biểu tượng không xác định:

nút <int> :: node (int)

phần lạ ... nếu tôi di chuyển hàm tạo từ tệp .cpp đến .h, mọi thứ đều hoạt động tốt. Vấn đề ở đâu?

Trả lời

23

Vấn đề là các mẫu không phải là các lớp - bạn thường không viết chúng trong hai tệp riêng biệt. Các lớp mẫu là mã mà trình biên dịch sử dụng để tạo ra các lớp. Như vậy, mã triển khai của bạn cần phải có hiệu quả nội dòng, tức là trong tiêu đề khi bạn phát hiện ra.

Để có giải thích đầy đủ hơn về lý do tại sao phải theo cách này, hãy xem C++ FAQ Lite.

13

Như một quy tắc chung, bạn phải đặt tất cả các thành viên mẫu bên trong tệp tiêu đề. Các mẫu được biên dịch trong một cơ sở được sử dụng, và do đó toàn bộ định nghĩa cần phải có sẵn ở bất cứ nơi nào chúng được sử dụng. Đặt mã trong tệp tiêu đề sẽ giải quyết vấn đề đó.

Lần duy nhất bạn có thể đặt định nghĩa mẫu trong tệp CPP là khi mẫu sẽ chỉ được sử dụng trong tệp CPP đó. Lý do là nó đáp ứng các tiêu chuẩn mà toàn bộ định nghĩa có sẵn để biên dịch.

Di chuyển nội dung của node.cpp sang nút.h sẽ khắc phục sự cố.

Kịch bản Strange

Sau đó, một lần nữa, bạn cũng có thể đặt tất cả mọi thứ trong một tập tin CPP và bao gồm các tập tin CPP. C++ là linh hoạt theo cách này. Tôi chỉ đề cập đến điều này vì tôi đã từng thấy trước đây. Tôi thực sự bầm tím hàm của mình khi nó chạm vào đỉnh bàn của tôi.

+1

Bạn cũng có thể đặt các chức năng thành viên templatized của một lớp không templatized vào file cpp nếu bạn không bao giờ gọi cho họ ở nơi khác (để thực thi điều này, họ nên riêng tư, nhưng chúng không nhất thiết phải). – rmeador

1

Khi bạn sử dụngnode<int>, bạn không có nhiều khả năng bao gồm node.cpp. Do đó trình biên dịch không thể khởi tạo hàm tạo node<int>::node<int>. Thông thường, bạn đặt tất cả mã mẫu, bao gồm tất cả các triển khai của các phương thức, trong tệp tiêu đề hoặc một thứ gì đó được bao gồm trong nó.

0

Trừ khi có cuộc gọi đến hàm, trình biên dịch sẽ không xuất ra bất kỳ mã nào và trình liên kết sẽ không tìm thấy nó.

Bạn nên đặt hàm vào tiêu đề của nó.

+0

Tôi vẫn chưa hiểu. Tại sao mẫu không thể là một lớp, với tiêu đề riêng biệt và mã nguồn? Giả sử tôi muốn viết Danh sách của riêng mình .. Tôi có phải bao gồm mọi phương thức Danh sách vào tệp tiêu đề không? –

+0

Vâng, đó là cách phổ biến nhất. Bạn cũng có thể #include "List.cpp" ở cuối List.h. –

+0

ok. Tôi tìm thấy nó lạ để bao gồm tất cả mọi thứ vào tập tin tiêu đề - mã thực tế là một chút dài hơn một vài dòng trong câu hỏi (đó là một cây tìm kiếm nhị phân). –

0

instantiation ngầm bị tắt, bạn cần

template class node<int>; 

nơi nào đó trong mã của bạn (node.cpp có thể)

EDIT: Câu trả lời xấu, nó có lẽ không phải là trường hợp.

+1

Nếu bạn nghĩ rằng đây là câu trả lời không tốt, bạn có thể xóa nó trước khi bạn bị downvoted. –

1

Thực tiễn thường được chấp nhận là đặt tất cả việc triển khai trong tệp .h, để các lớp có thể được tạo từ mẫu khi cần.

Nếu bạn biết trước thời gian các loại mẫu của bạn sẽ được khởi tạo, bạn có thể lừa một chút. Chỉ cần đảm bảo .cpp của bạn bao gồm một trường hợp sử dụng cho từng loại và phương pháp bạn sẽ cần. Điều quan trọng là trường hợp sử dụng đến sau mã mẫu. Ví dụ. cho "node.cpp", sử dụng

#include "node.h" 

template<class T> 
node<T>::node (T data) { 
    _data = data; 
} 

void dummy(void) 
{ 
    node<int> intnode(0); 
    node<double> doublenode(0.0); 
} 
1
// You can put templates declaration in header and definition in source 
// node.h or wherever you include file gets included 
extern template class node<int>; 

// node.cpp or where ever source file you want to use it 
// But use it only once for each type of generated class 
template class node<int>;