C ++中部分类函数覆盖的问题

时间:2010-01-13 15:29:50

标签: c++ inheritance

是否存在部分覆盖由基类定义的一组虚函数的问题?

我的编译器提供以下警告:

overloaded virtual function "MyBaseClass::setValue" is only partially overridden in class "MyDerivedClass".

这些课程如下:

class MyBaseClass
{
public:
    virtual void setValue(int);
    virtual void setValue(SpecialType*);
}

class MyDerivedClass : public MyBaseClass
{
public:
    virtual void setValue(int);
}

摆脱此警告的简单方法是为基本功能使用不同的名称,但我想知道是否有任何令人信服的理由来修复此特定警告。我不相信这违反了C ++标准。我的猜测是警告程序员他们可能忘记为所有可能的输入类型实现行为。在我们的例子中,有意排除某些特定类型。

你会不鼓励完全压制这个警告吗?

3 个答案:

答案 0 :(得分:13)

setValue(int)的覆盖隐藏了基类的setValue(SpecialType*)(请参阅C++ FAQ Lite),因此如果您尝试拨打setValue(new SpecialType()),则会收到错误。

您可以通过向派生类添加using指令来避免这种情况,该派生类从基类“导入”重载:

class MyDerivedClass : public MyBaseClass
{
public:
    using MyBaseClass::setValue;
    virtual void setValue(int);
};

答案 1 :(得分:6)

警告是正确的,它被称为“名字隐藏”。 MyDerivedClass类型的变量无法调用setValue(SpecialType*)

<小时/> 现在我要公然扯掉someone else's blog

在C ++中重载和名称隐藏

  

昨晚在与布拉德的电话交谈中,他告诉我他在新的C ++工作中遇到的一个奇怪的问题。当然,对于拥有丰富C ++经验的人来说,这可能没什么大不了的,但对于我们这些生活在托管代码世界中的人来说,这似乎很奇怪。

     

在C ++中,当你有一个带有重载方法的类(成员函数,无论你想要调用它),然后扩展并覆盖该方法时,你必须覆盖所有重载的方法。

     

我理解您在子类中更改了方法签名的情况,从而使已建立的接口无效。但是,在这种情况下,它似乎违反直觉,因为您不是在更改界面,而是选择性地覆盖。哪个是不同的。

     

例如:

class FirstClass
{
public:
        virtual void MethodA (int);
        virtual void MethodA (int, int);
};

void FirstClass::MethodA (int i)
{
    std::cout << "ONE!!\n";
}

void FirstClass::MethodA (int i, int j)
{
     std::cout << "TWO!!\n";
}
  

这里有两个方法(或一个重载方法)的简单类。您想要覆盖双参数版本,因此继续以下操作:

class SecondClass : public FirstClass
{
public:
    void MethodA (int);
};

void SecondClass::MethodA (int i)
{
    std::cout << "THREE!!\n";
}
  

现在,当您使用SecondClass的实例时,大多数Java或C#程序员可能会假设您可以调用:

int main ()
{
    SecondClass a;
    a.MethodA (1);
    a.MethodA (1, 1);
}
  

但是,第二次调用无效,因为双参数MethodA不可见。您可以获取指针并向上转换为FirstClass,但您的SecondClass实例不会直接继承未重写的方法。

答案 2 :(得分:0)

很明显,编译器想要警告你:你创建了一个子类,当给它一个int时行为不同,但是在给它SpecialType*时你并没有改变它的行为。

虽然可能是意图,但很有可能其他重载虚拟函数也需要更改行为。

我希望编译器更加警告我,我忽略了它!我的被​​覆盖的方法在我的场景中被编译并运行良好,但由于过载未被覆盖,其他一些场景出现了问题。

在禁用该警告之前请三思而后行!

如果您希望保留原始行为,则只需调用父函数即可:

class MyDerivedClass : public MyBaseClass {
   virtual void setValue(int);
   // explicit: keep original behavior for SpecialType
   virtual void setValue( SpecialType* p ) { MyBaseClass::setValue(p); } 
};