2011-08-06 39 views
8

Tôi có một tập tin gọi là "SimpleFunctions.h" được định nghĩa như sau:Chức năng đã được xác định lỗi trong C++

#ifndef SIMPLEFUNCTIONS_H 
#define SIMPLEFUNCTIONS_H 

namespace my_namespace { 

double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); } 
float round(float r) { return round((double)r); } 

} 

#endif // SIMPLEFUNCTIONS_H 

tập tin này trước đây đã được đưa vào chỉ có một tập tin và nó đã làm việc tốt.

Hôm nay, hôm nay tôi đã đưa nó vào tệp thứ hai và nó không hoạt động nữa. Tại thời gian liên kết, nó cho tôi biết rằng hàm đã được định nghĩa trong "firstfile.obj".

Tuy nhiên, vì tôi đang sử dụng bao gồm bảo vệ, tôi sẽ mong đợi các chức năng được xác định chỉ một lần, hoặc tôi thiếu một cái gì đó?

Trả lời

17

Theo mặc định, các chức năng này có liên kết bên ngoài. Điều đó có nghĩa là mỗi đơn vị dịch thuật có các hàm được gọi là vòng kép (double r) và vòng float (float r), gây ra xung đột tên tại thời gian liên kết.

Một số giải pháp có thể là:

  1. Khai báo các chức năng như tĩnh, trong đó hàm ý liên kết nội bộ
  2. Inline chức năng
  3. Di chuyển việc thực hiện ra khỏi header và vào ac nộp/C++

Đọc thêm tại đây: What is external linkage and internal linkage?

Nhân tiện, bao gồm các nhân viên bảo vệ một đơn vị dịch thuật duy nhất bao gồm một tệp tiêu đề nhiều lần. Đó là một vấn đề khác mà bạn đang thấy ở đây.

+0

Bạn chính xác. Đây là lý do tại sao bạn nên tránh thực hiện các chức năng bên trong các tiêu đề. –

+0

'inline' không _not_ ngụ ý liên kết giữa các bên. http://stackoverflow.com/questions/4957582/how-can-i-prove-that-inline-functions-default-to-internal-linkage –

+0

@Charles: lỗi của tôi - Tôi đã chỉnh sửa câu trả lời – pepsi

2

sử dụng 'inline'

inline double round(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); } 
inline float round(float r) { return round((double)r); } 

Trình biên dịch sẽ không nhất thiết inline mã (mặc dù cho điều này ngắn func nó có thể) nhưng mối liên kết không điều trị là như một chức năng riêng biệt nữa. Lưu ý - bao gồm bảo vệ ngăn chặn cùng bao gồm các tập tin được bao gồm nhiều hơn một lần trong cùng một tập tin nguồn (nghiêm túc nói 'biên soạn đơn vị') nó không dừng nó được bao gồm trong các tập tin nguồn riêng biệt được liên kết với nhau. Đó là lý do tại sao bạn thường khai báo nó trong tiêu đề nhưng xác định hàm trong một tệp c

+0

Điều đó có hiệu quả, cảm ơn. Tôi đang tò mò mặc dù - tại sao trình biên dịch bao gồm các tập tin hai lần mặc dù có một bảo vệ bao gồm? –

+0

Tôi cũng muốn biết! :) – Casey

+1

Đó là một đơn vị dịch thuật riêng biệt - định nghĩa macro không bao gồm đơn vị dịch (trình biên dịch trình biên dịch). Trình liên kết hiện có 2 định nghĩa về vòng và lỗi. 'static' cũng đúng để giải quyết vấn đề. –

1

Cách tốt hơn để giải quyết vấn đề là thông qua các mẫu. Mã của bạn sẽ biên dịch tốt nếu bạn phải làm điều gì đó dọc theo các dòng:

template <class T> 
T round (T r) { 
    return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); 
} 

Trình liên kết của bạn sẽ ngừng phàn nàn và bạn sẽ có một chức năng duy nhất cho mọi nhu cầu của mình.

Giải pháp này có thể được cải thiện với các đặc điểm kiểu. Xem boost::is_floating_pointboost::enable_if

+0

Bạn lừa dối, nhưng theo một cách tốt. Nó hoạt động. Nó thậm chí còn là giải pháp tốt nhất cho các tình huống nhất định! Cảm ơn. – javaLover

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