2017-12-25 113 views
7

Ví dụC++ bao gồm tập tin tiêu đề khác nhau với cùng một thực hiện của lớp trong nhiều file nguồn

a.h

class Dummy { 
public: 
    Dummy() { std::cout << "a.h" << std::endl; } 
}; 

b.h

class Dummy { 
public: 
    Dummy() { std::cout << "b.h" << std::endl; } 
}; 

c.cc

#include "a.h" 

void test() { 
    Dummy a; 
} 

d.cc

#include "b.h" 

int main() { 
    Dummy a; 
    return 0; 
} 

Sau đó biên dịch file nguồn với lệnh

g++ d.cc c.cc 

ra là

b.h 

nhưng với lệnh

012.
g++ c.cc d.cc 

ra là

a.h 

Câu hỏi của tôi là lý do tại sao không có multiple definition lỗi và lý do tại sao sản lượng phụ thuộc vào trật tự biên soạn không?

+0

'A a' là gì? Ý bạn là 'Dummy a'? – Mixhab

+1

Hàm tạo của 'Dummy' không được định nghĩa giống nhau trong cả hai tệp tiêu đề. Kết quả là do đó hành vi không xác định - mà một trình biên dịch là không cần thiết để chẩn đoán. d.cc sẽ không biên dịch vì không có định nghĩa về lớp 'A'. – Peter

+0

@Mixhab cố định, nhờ – Scy

Trả lời

8

Chương trình của bạn có hành vi không xác định. Để tóm tắt C++ mất tiêu chuẩn của, đây là [basic.def.odr/6] với sự nhấn mạnh của tôi:

Có thể có nhiều hơn một định nghĩa của một kiểu lớp, [...] trong một chương trình với điều kiện là mỗi định nghĩa xuất hiện trong một dịch khác nhau đơn vị, và cung cấp các định nghĩa đáp ứng các yêu cầu sau đây. Với một thực thể như vậy được đặt tên D quy định tại nhiều đơn vị dịch, sau đó

  • mỗi định nghĩa của D sẽ bao gồm cùng một chuỗi các thẻ; và

  • [...]

[...] Nếu các định nghĩa của D đáp ứng tất cả các yêu cầu này, sau đó hành vi là như nếu có một định nghĩa duy nhất của D. Nếu các định nghĩa của D không thỏa mãn các yêu cầu này, thì hành vi không được xác định.

Vì vậy, bạn quan sát hai hành vi khác nhau. Hoàn toàn có thể chấp nhận được, vì ngôn ngữ không bị hạn chế về hành vi mà bạn thậm chí sẽ thấy. Bạn đã vi phạm hợp đồng, vì vậy không có bảo đảm nào.

Bây giờ, từ quan điểm thực tế, những gì bạn thấy xảy ra chỉ là GCC hoạt động theo hợp đồng trên.Nó giả định bạn sẽ không vi phạm nó (ngay cả khi bạn làm), và chỉ bỏ qua bất kỳ định nghĩa lại sau đó của Dummy và/hoặc các thành viên của nó. Người đầu tiên "thắng".

3

Trình biên dịch không phát hiện lỗi nhiều định nghĩa vì c.ccd.cc là riêng biệt đơn vị dịch. Chúng được xử lý riêng biệt với nhau; mỗi cái có một định nghĩa chính xác là Dummy::Dummy hàm tạo.

Trình liên kết không phát hiện lỗi nhiều định nghĩa vì định nghĩa của Dummy::Dummy hàm tạo từ tiêu đề được coi là định nghĩa nội tuyến. Ngôn ngữ cho phép định nghĩa nội tuyến trong mỗi đơn vị dịch, miễn là tất cả chúng đều giống hệt nhau. Thông thường, lý do mà các định nghĩa này giống hệt nhau là tất cả chúng đều xuất phát từ cùng một tệp tiêu đề, nhưng tiêu chuẩn yêu cầu các định nghĩa giống hệt nhau ngay cả khi chúng đến từ các tệp khác nhau.

Khi chương trình của bạn vi phạm quy tắc này, hành vi của nó không xác định. Đó là lý do tại sao chương trình của bạn hoạt động khác nhau tùy thuộc vào hành động dường như không liên quan đến việc thay đổi thứ tự các đơn vị dịch thuật trong quá trình dịch.

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