C++ c++;通过叮当声发出过载虚拟函数警告?
编译以下代码时,clang会发出警告:C++ c++;通过叮当声发出过载虚拟函数警告?,c++,warnings,overloading,virtual,hidden,C++,Warnings,Overloading,Virtual,Hidden,编译以下代码时,clang会发出警告: 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); }; 警告是: warning: 'Derived::get' hides overloaded virtual f
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);
};
警告是:
warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]
(当然,需要启用上述警告)
我不明白为什么。请注意,在Base中取消对同一声明的注释会关闭警告。我的理解是,由于两个get()函数具有不同的签名,因此不能隐藏
叮当声对吗?为什么?
注意,这是在MacOS X上,运行最新版本的Xcode
clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)
更新:与Xcode 4.6.3的行为相同。此警告用于防止在打算重写时意外隐藏重载。考虑一个稍微不同的例子:
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
};
由于这是一个警告,并不一定意味着这是一个错误,但它可能表明一个错误。通常,这样的警告可以通过更明确的方式关闭它们,并让编译器知道您确实打算写什么。我相信在这种情况下,您可以做到以下几点:
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);
};
警告意味着,不会有 void*get(char*e) 函数在派生类的作用域中,导致它被另一个同名方法隐藏。 若派生类至少有一个具有指定名称的方法,即使它有另一个参数,编译器也不会在基类中搜索函数 此示例代码不会编译:
class A
{
public:
virtual void Foo() {}
};
class B : public A
{
public:
virtual void Foo(int a) {}
};
int main()
{
B b;
b.Foo();
return 0;
}
R.Martinho Fernandes如果您确实想将使用单个char*参数的
get()
方法引入派生的范围,那么解决方案是完全有效的
实际上,在您提供的代码段中,不需要虚拟方法(因为Base和Derived不共享任何具有相同签名的方法)
假设确实需要多态性,隐藏行为仍然可能是预期的。
在这种情况下,可以使用以下pragma本地禁用Clang的警告:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
// Member declaration raising the warning.
#pragma clang diagnostic pop
另一种禁用警告并保持结构公共接口完整的方法是:
struct Derived: public Base
{
virtual void * get(char* e, int index);
private:
using Base::get;
};
这不允许Derived
的使用者在关闭警告时调用Derived::get(char*e)
:
Derived der;
der.get("", 0); //Allowed
der.get(""); //Compilation error
这是一个很好的观点:隐藏实际上正在积极发生,即使不同的签名应该足以阻止它。我对隐藏的定义是拥有相同的签名,但不覆盖。。。这里不是这样的。从C++中避免隐藏的解决方法:“如果你希望编译器把基类函数看作候选”,在派生类中插入一个使用声明,如其他答案所示。如果它也包含一个解决方案(使用…),这应该是可接受的答案。因为这是唯一一个正确解释发生了什么以及为什么这是一个有效的警告的方法,我认为这是最清楚的答案。然而值得注意的是,您实际上仍然可以调用b.Foo()代码>。您只需要编写b.A::Foo()
。可以指出的是,这种“本地关闭警告”的解决方案也改变了代码的语义:您现在可以使用静态类型派生的对象上的单个参数调用get
函数成员。如果没有using声明,同样的事情也会导致编译错误。这个答案令人倍感惊讶。起初,这正是我所寻找的答案,我“希望我的方法在那里”。由于pragma的原因,我在代码中写了一条注释&叮当声多么愚蠢,我的眼睛发现我写了override,但是警告太多了。然后我点击并意识到我忘记了继承的方法的const,而clang一直都是正确的。如果有疑问,请信任编译器。当您怀疑编译器时,请信任编译器。:)+1因为他们都给了我所追求和需要的东西!当您计划替换基类的classget
方法时,这绝对是删除此警告的安全方法!但是,请注意,这会导致呼叫不明确的情况。所以这个解决方案也不是100%节省。