2012-06-20 38 views
18

Tôi hy vọng danh hiệu thực sự mô tả những gì tôi muốn hỏi ...C++ gọi phương thức và loại có độ phân giải phạm vi nhập nhằng

Tôi đã viết một đoạn mã mà biên dịch với gcc và các công trình như tôi mong muốn. Tuy nhiên, nó không biên dịch với llvm và mã thực thi khác khi được biên dịch với icc!
Dưới đây là một ví dụ về các vấn đề:

#include <iostream> 

using std::cout; using std::endl; 

class A { 
public: 
    virtual void foo() { cout << "A::foo()" << endl; } 
}; 

class B : public A { 
public: 
    typedef A base; 
    virtual void foo() { cout << "B::foo()" << endl; } 
}; 

int main() { 
    typedef B base; 
    base* bp = new B(); 
    bp->base::foo(); 
} 

gcc đầu ra: A :: foo()
icc đầu ra: B :: foo()

ai đó có thể giải thích những gì hiện tiêu chuẩn nói về trường hợp này?

+5

Tôi sẽ nói đó là lỗi trong GCC và ICC, vì 'B :: base' không phải là _member_ của' B', có nghĩa là không nên truy cập nó như một thành viên ('bp-> base'). –

+1

Tôi đồng ý với @JoachimPileborg, hơn nữa 'cơ sở' có thể được hiểu là B trong phạm vi này. Bạn đã biên soạn với cờ Cảnh báo chưa? (-Wall cho gcc) – Geoffroy

+1

Không phải chỉ là hành vi không xác định, bởi vì 'main' không phải là dạng yêu cầu? Có vẻ như tất cả các trình biên dịch đều đúng. –

Trả lời

7

Từ C++ 11, §3.4.5/4:

Nếu biểu thức id trong quyền truy cập của thành viên lớp là id đủ điều kiện của biểu mẫu
 
    class-name-or-namespace-name::... 
tên lớp hoặc tên không gian tên theo sau. hoặc -> toán tử đầu tiên được tra cứu trong lớp của biểu thức đối tượng và tên, nếu tìm thấy, được sử dụng. Nếu không, nó là tra cứu trong ngữ cảnh của toàn bộ biểu thức postfix.

Tôi không nghĩ rằng điều đó có thể rõ ràng hơn. Điều này tìm thấy B::base, do đó, đầu ra phải là A::foo().

+0

Cảm ơn bạn đã trợ giúp, các bạn thật tuyệt vời. Đoạn đặc biệt này thực sự rất rõ ràng và chính xác cho điểm! – Nowakus

6

Tôi nghĩ rằng phần này của tiêu chuẩn có liên quan:

3.4.3.1 viên Lớp [class.qual]

1) Nếu lồng nhau-tên-specifier của một trình độ-id đề cử một lớp, tên được chỉ định sau bộ mã định danh lồng nhau được tra cứu trong phạm vi của lớp (10.2), ngoại trừ các trường hợp được liệt kê bên dưới. Tên phải đại diện cho một hoặc thành viên khác của lớp đó hoặc của một trong các lớp cơ sở của nó (Điều 10). [Lưu ý: Thành viên của lớp học có thể được giới thiệu bằng cách sử dụng id đủ điều kiện tại bất kỳ địa chỉ nào trong phạm vi tiềm năng của nó (3.3.7). —khi lưu ý] Các ngoại lệ đối với quy tắc tra cứu tên trên đây là:

- tên hủy là tra cứu như được chỉ định trong 3.4.3;

- id chuyển đổi loại của chức năng chuyển đổi-id được tra cứu theo cách tương tự như loại chuyển đổi-id trong quyền truy cập của thành viên nhóm (xem 3.4.5);

- tên trong mẫu-đối số của mẫu-id được tra cứu trong ngữ cảnh trong đó toàn bộ biểu thức hậu tố xảy ra.

- tra cứu tên được chỉ định trong khai báo sử dụng (7.3.3) cũng tìm thấy tên lớp hoặc liệt kê ẩn trong cùng phạm vi (3.3.10).

base:: trong trường hợp này có vẻ như "chỉ định" một lớp, vì vậy việc tra cứu được thực hiện trong phạm vi của lớp học. Tôi không thấy bất kỳ trường hợp ngoại lệ nào có thể áp dụng, vì vậy nó là phạm vi của lớp, như vậy base tương đương với A.

(5.1.1-8 chỉ ra rằng nó là một trình độ-id trong trường hợp đó và 3.4.3.1 được áp dụng)

+0

Đồng ý. Nó có vẻ khá rõ ràng với tôi là tốt. Mã này đúng, được xác định rõ và đầu ra phải là 'A :: foo'. –

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