2013-08-29 36 views
46

kêu vang phát ra một cảnh báo khi biên dịch đoạn mã sau:C++ quá tải cảnh báo chức năng ảo bằng tiếng kêu?

struct Base 
{ 
    virtual void * get(char* e); 
// virtual void * get(char* e, int index); 
}; 

struct Derived: public Base { 
    virtual void * get(char* e, int index); 
}; 

Cảnh báo là:

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual] 

(cảnh báo cho biết cần phải được bật tất nhiên).

Tôi không hiểu tại sao. Lưu ý rằng bỏ ghi chú tương tự trong Base sẽ tắt cảnh báo. Sự hiểu biết của tôi là vì hai hàm get() có các chữ ký khác nhau nên không thể ẩn.

Có phải tiếng kêu phải không? Tại sao?

Lưu ý đây là trên MacOS X, đang chạy phiên bản Xcode gần đây.

clang --version 
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn) 

Cập nhật: hành vi tương tự với Xcode 4.6.3.

Trả lời

77

Cảnh báo này là để ngăn chặn tình cờ quá tải khi ghi đè được dự định. Hãy xem xét một ví dụ hơi khác:

struct chart; // let's pretend this exists 
struct Base 
{ 
    virtual void* get(char* e); 
}; 

struct Derived: public Base { 
    virtual void* get(chart* e); // typo, we wanted to override the same function 
}; 

Vì đây là cảnh báo, điều đó không nhất thiết có nghĩa là sai, nhưng nó có thể chỉ ra một. Thông thường cảnh báo như vậy có một phương tiện tắt chúng bằng cách rõ ràng hơn và để cho trình biên dịch biết bạn đã có ý định những gì bạn đã viết. Tôi tin rằng trong trường hợp này bạn có thể làm như sau:

struct Derived: public Base { 
    using Base::get; // tell the compiler we want both the get from Base and ours 
    virtual void * get(char* e, int index); 
}; 
+1

xuất sắc như thường lệ ... Cảm ơn –

+7

Có thể chỉ ra rằng, giải pháp để "tắt cảnh báo cục bộ" này cũng đang thay đổi ngữ nghĩa của mã: bây giờ bạn có thể gọi thành viên hàm 'get' với một đối số duy nhất trên một đối tượng kiểu tĩnh' Derived'. Nếu không có khai báo sử dụng, điều tương tự sẽ dẫn đến một lỗi biên dịch. –

10

phương tiện cảnh báo, rằng sẽ không có void * get (char e *) chức năng trong phạm vi của lớp nguồn gốc, nguyên nhân nó ẩn bằng phương pháp khác có cùng tên. Trình biên dịch sẽ không tìm kiếm hàm trong các lớp cơ sở nếu lớp dẫn xuất có ít nhất một phương thức có tên được chỉ định, ngay cả khi nó có một đối số khác.

Mẫu này mã sẽ không biên dịch:

class A 
{ 
public: 
    virtual void Foo() {} 
}; 

class B : public A 
{ 
public: 
    virtual void Foo(int a) {} 
}; 


int main() 
{ 
    B b; 
    b.Foo(); 
    return 0; 
} 
+0

Đó là một điểm tốt: ẩn là * thực sự * * chủ động * xảy ra, mặc dù các chữ ký khác nhau là đủ để ngăn chặn nó. –

+0

Định nghĩa của tôi về ẩn là có chữ ký giống nhau nhưng không ghi đè ... đó không phải là trường hợp ở đây. – NGauthier

+0

Các giải pháp để tránh ẩn, từ __C++ trong một Nutshell__: "Chèn một khai báo sử dụng trong lớp dẫn xuất nếu bạn muốn trình biên dịch xem xét các hàm lớp cơ sở như các ứng viên", như được hiển thị trong các câu trả lời khác. – qris

18

R. Martinho Fernandes giải pháp là hoàn toàn hợp lệ nếu bạn thực sự muốn mang get() phương pháp tham gia một char duy nhất * đối số vào Derived phạm vi.

Thực ra, trong đoạn mã bạn đã cung cấp, không cần các phương thức ảo (vì Base và Derived không chia sẻ bất kỳ phương thức nào có cùng chữ ký).

Giả sử có thực sự là một nhu cầu về đa hình, hành vi ẩn có thể vẫn là những gì được dự định. Trong trường hợp này, nó có thể ở địa phương vô hiệu hóa cảnh báo Clang, với các pragma sau:

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Woverloaded-virtual" 
    // Member declaration raising the warning. 
#pragma clang diagnostic pop 
+0

Câu trả lời này đáng kinh ngạc gấp đôi. Lúc đầu nó là câu trả lời chính xác cho những gì tôi đang tìm kiếm, rằng tôi "muốn phương pháp của tôi ra khỏi đó". Khi tôi đang viết một bình luận trong mã của tôi vì lý do của pragma và làm thế nào kêu vang là ngu ngốc, đôi mắt của tôi bắt gặp rằng tôi đã viết đè lên, nhưng cảnh báo đã quá tải. Sau đó, tôi nhấp & nhận ra rằng tôi đã quên 'const' trên phương thức kế thừa, và clang đã đúng. Khi nghi ngờ, hãy tin tưởng trình biên dịch. Khi bạn nghi ngờ trình biên dịch, hãy tin tưởng trình biên dịch. :) 1 cho cả hai cho tôi cả những gì tôi tìm kiếm và cần thiết! – nevelis

11

Một cách khác để vô hiệu hóa các cảnh báo giữ public interface struct nguyên vẹn sẽ là:

struct Derived: public Base 
{ 
    virtual void * get(char* e, int index); 
private: 
    using Base::get; 
}; 

Không cho này một người tiêu dùng của Derived gọi Derived::get(char* e) trong khi bịt miệng cảnh báo:

Derived der; 
der.get("", 0); //Allowed 
der.get(""); //Compilation error 
Các vấn đề liên quan