2012-05-25 29 views
17

xem xét tập tin này, first.cpp, chứa một định nghĩa lớp và sử dụng:Tại sao liên kết ld cho phép nhiều định nghĩa lớp có cùng phương pháp?

#include <iostream> 

struct Foo 
{ 
    Foo(){ std::cout << "Foo()" << std::endl; } 
    ~Foo(){ std::cout << "~Foo()" << std::endl; } 
}; 

int main(){ 
    Foo f; 
    return 0; 
} 

và khác, second.cpp, chứa một định nghĩa lớp mâu thuẫn:

#include <iostream> 

struct Foo 
{ 
    Foo(); 
    ~Foo(); 
}; 

Foo::~Foo(){ std::cout << "wrong ~Foo()" << std::endl; } 

Các mối liên kết phàn nàn về những biểu tượng trùng lặp khi có hai các hàm có cùng tên được xác định, nhưng những tệp này có các phương thức lớp trùng lặp biên dịch mà không có lỗi.

tôi biên soạn với các lệnh:

$ g++ -c second.cpp -o second 
$ g++ second first.cpp -o first 

Sắp xếp lại các đối số thứ hai g++ cuộc gọi không thay đổi sản lượng.

Và khi first đang chạy, đây là kết quả:

$ ./first 
Foo() 
wrong ~Foo() 

Tại sao mối liên kết cho phép các phương thức lớp trùng lặp? Nếu nó được cho phép, tại sao là wrong ~Foo() được in?

+0

Tôi nghĩ rằng nó phụ thuộc vào phiên bản của trình biên dịch, nhưng phải mất một trong những đầu tiên mà nó tìm thấy. – Brady

+0

Đó là GCC 4.6.1. –

+3

Nó có thể là một cái gì đó để làm với chức năng inlining nhường chỗ cho một chức năng tập tin đối tượng mà nó hiện diện. Tôi đoán bạn sẽ có cùng một vấn đề với các nhà xây dựng nếu bạn tuyên bố một phiên bản không inline trong second.cpp và vấn đề sẽ biến mất nếu cả hai nguồn tuyên bố các chức năng nội tuyến. – forsvarir

Trả lời

14

Một lần nữa, Hành vi không xác định. Chương trình của bạn có nhiều định nghĩa cho destructor của Foo, có nghĩa là nó vi phạm ODR. Chương trình là sai và bất cứ điều gì có thể happend.

Tại sao trình liên kết không nhận được? Khi một hàm được định nghĩa bên trong định nghĩa lớp, nó là hoàn toàn inline. Trình biên dịch thường đánh dấu các chức năng đó là 'biểu tượng yếu'. Sau đó, trình liên kết sẽ nhận tất cả các đơn vị dịch và cố gắng giải quyết các ký hiệu. Các ký hiệu yếu sẽ bị trình liên kết thả xuống nếu cần (tức là nếu biểu tượng đã được xác định ở một nơi khác).

Do đầu ra thực tế của chương trình, có vẻ như trình biên dịch không thực sự chuyển nội dung cuộc gọi tới hàm tạo và do đó được gửi vào thời gian chạy tới biểu tượng đã được liên kết trái (số không yếu)


Tại sao trình liên kết cho phép có phương pháp trùng lặp?

Bởi vì tất cả (nhưng tối đa là một) là biểu tượng yếu (ví dụ: inline)

Tại sao, trong trường hợp này, sai ~ Foo() được in?

Bởi vì các cuộc gọi không được sắp xếp theo hàng và các mối liên kết giảm các biểu tượng yếu

+1

Đối với một số lý do nhìn thấy ** Hành vi không xác định ** in đậm làm cho tôi tất cả ham chơi. –

+0

@ChetSimpson: Cái xấu của tôi, câu hỏi này rất giống với câu hỏi khác từ hôm nay, câu trả lời là UB. Điều này gần như giống nhau, tôi nhầm lẫn cho rằng cùng một người đã nhấn mạnh vào việc đi bộ cạnh chảy máu, nhưng trong nhận thức có vẻ như hai câu hỏi được hỏi bởi những người khác nhau. –

+0

@@ david-rodriguez-dribeas Tất cả đều tốt, UB cần được in đậm tất cả bây giờ và một lần nữa;) –

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