Do Derured1 :: Base và Derured2 :: Base có cùng loại không?


12

MSVC, Clang và GCC không đồng ý với mã này:

struct Base { int x; };
struct Der1 : public  Base {};
struct Der2 : public  Base {};

struct AllDer : public Der1, public Der2 {
    void foo() {
        Der1::Base::x = 5;
    }
};

Thần may mắn

GCC:

<source>: In member function 'void AllDer::foo()':    
<source>:10:21: error: 'Base' is an ambiguous base of 'AllDer'    
   10 |         Der1::Base::x = 5;    
      |                     ^    
Compiler returned: 1

Clang đưa ra một lỗi tương tự và MSVC không có lỗi.

Ai ở ngay đây?

Tôi cho rằng điều này được đề cập trong [class.member.lookup] , nhưng tôi gặp khó khăn trong việc hiểu những gì nó đang cố nói với tôi cho trường hợp này. Vui lòng trích dẫn các phần có liên quan và nếu có thể giải thích bằng tiếng Anh.

PS: Lấy cảm hứng từ câu hỏi này Tại sao Tham chiếu đến Lớp cơ sở mơ hồ với lớp dẫn xuất máng :: -operator?

PPS: Trên thực tế, nghi ngờ của tôi là liệu Der1::Basetham chiếu đến loại, đó sẽ là Base(và sau đó Der2::Basechính xác là cùng loại) hay với tiểu dự án. Tôi tin rằng đó là cái đầu tiên, nhưng nếu nó là cái sau thì MSVC sẽ đúng.



@L LanguageLawyer gợi ý tốt hơn rằng gcc và clang là đúng, nhưng tôi không hoàn toàn tin rằng mscv sai
idclev 463035818

1
Rõ ràng cả hai đều đề cập đến cùng một loại ::Base, nhưng câu hỏi thực sự có vẻ hơi khác nhau ở đây. Có hai tiểu loại loại Basevà cả hai đều có Base::x thành viên.
MSalters

@MSalters PPS chỉ thể hiện sự nhầm lẫn của tôi. Nếu bạn có đề xuất cho một tiêu đề tốt hơn, vui lòng chỉnh sửa, tôi không thích nó (vì tôi biết câu trả lời là có), nhưng không tìm thấy thứ gì phù hợp hơn
idclev 463035818

1
@ d4rk4ng31 không có sự kế thừa ảo trong mã (về mục đích)
idclev 463035818

Câu trả lời:


6

Để trả lời câu hỏi trong tiêu đề, vâng, Derived1::Basetham chiếu tên lớp được chèn [class.pre] Base và cũng vậy Derived2::Base. Cả hai đều tham khảo lớp học ::Base.

Bây giờ, nếu Basecó một thành viên tĩnhx , thì việc tra cứu Base::xsẽ không rõ ràng. Chỉ có một.

Vấn đề trong ví dụ này xlà một thành viên không tĩnh và AllDerhai thành viên như vậy. Bạn có thể định hướng truy cập như vậy xbằng cách chỉ định một lớp cơ sở rõ ràngAllDer chỉ có một xthành viên. Derived1là một lớp cơ sở rõ ràng và nó có một xthành viên, vì vậy Derived1::xrõ ràng chỉ định rõ ràng xthành viên nào trong hai thành viên trong AllDerbạn. Basecũng chỉ có một xthành viên, nhưng nó không phải là một cơ sở rõ ràng AllDer. Mỗi trường hợp AllDercó hai đối tượng phụ của loại Base. Do đó Base::xlà mơ hồ trong ví dụ của bạn. Và vì Derived1::Basechỉ là một tên khác cho Base, điều này vẫn còn mơ hồ.

[class.member.lookup] chỉ định xđược tra cứu trong ngữ cảnh của trình xác định tên lồng nhau, do đó phải được giải quyết trước. Chúng tôi thực sự đang tìm kiếm Base::x, không Derived1::x, bởi vì chúng tôi đã bắt đầu bằng cách giải quyết Derived1::Basenhư Base. Phần này thành công, chỉ có một xtrong Base.Note 12 trong [class.member.lookup] cho bạn biết rõ rằng việc sử dụng tra cứu tên không rõ ràng vẫn có thể thất bại khi có nhiều tiểu dự án có cùng tên đó. D::itrong ví dụ đó về cơ bản là của bạn Base::x.


vậy nó chỉ "có thể thất bại" chứ không phải "phải thất bại" và cả ba trình biên dịch đều đúng? Xem xét ví dụ a template <typname A,typename B> struct foo : A,Bvới một số mã được truy cập để truy cập các thành viên của một cơ sở AB. Trong trường hợp như vậy tôi muốn nhận được một lỗi
idclev 463035818

1
@ idclev463035818: Tôi nghi ngờ đó là chẩn đoán "phải thất bại" bắt buộc . Cụ thể, điều này không thành công khi truy cập thành viên Lớp 7.6.1.4/7, "không thành hình".
MSalters

Tôi phải đọc thêm một chút. Và tôi phải thực hiện một số nghiên cứu về msvc, tôi nghi ngờ rằng cần có một số cờ để có đầu ra tuân thủ đầy đủ, nhưng phải tìm ra cờ nào
idclev 463035818

2

Lý do bạn có thể gọi tên lớp là thành viên của lớp là vì cpp bí danh nó để sử dụng thuận tiện, như thể bạn đã viết using Base = ::Base;bên trong Base.
Vấn đề bạn đang phải đối mặt là Der1::BaseBase.
Vì vậy, khi bạn viết Der1::Base::x, nó giống như Base::x.


Tôi biết "vấn đề" là gì nhưng bạn không trả lời câu hỏi của tôi: "Ai đúng? (Và tại sao?)"
idclev 463035818

@ idclev463035818: Tôi tin rằng đây là mặt phải. Phần về usingđược viết theo tiêu chuẩn và tôi nghĩ đó là chìa khóa để diễn giải những gì biểu thức nói.
Dani

@ idclev463035818: Xem ví dụ sau. Tôi nghĩ rằng nó sẽ xóa nó một chút. ideone.com/IqpXjT
Dani

xin lỗi nhưng tôi nghĩ bạn không hiểu ý tôi. Tôi muốn biết những gì là đúng theo tiêu chuẩn, bởi vì tôi thấy trình biên dịch khác nhau làm những việc khác nhau. Nhìn vào những gì một trình biên dịch cụ thể làm với một ví dụ cụ thể, không giúp trả lời câu hỏi
idclev 463035818

Chỉ cần FYI, MSVC (ver 19.25.28614 cho x64) không thể biên dịch ví dụ của bạn tại ideone.com/IqpXjT . Sử dụng cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cppnhư dòng lệnh của nó, tôi nhận đượcmain.cpp(7): error C2597: illegal reference to non-static member 'A::x'
heap vượt qua
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.