代码之家  ›  专栏  ›  技术社区  ›  Andrew KeepCoding

具有默认参数更改行为的虚拟方法[重复]

  •  0
  • Andrew KeepCoding  · 技术社区  · 1 年前

    我被要求对使用Visual Studio 2013 VC++构建的旧项目进行轻微更改。所以,我安装了VS2013,进行了更改,编译了它,但它的行为在我没有接触的代码上发生了变化。

    更新后,在派生类上调用方法的虚拟方法现在正在基类上调用方法。

    我不是C++专家,但我可以看出这是一个糟糕的做法。我只想知道C++是否有突破性的变化,这样我就可以向要求我更新这个项目的人解释了。

    class BaseItem
    {
      public:
        virtual void SetValue(int first, int* second = nullptr)
        {
        };
    }
    
    class DerivedItem : public BaseItem
    {
      public:
        virtual void SetValue(int first)
        {
        };
    }
    
    BaseItem* item = new DerivedItem();
    // Before: SetValue on the DerivedItem was called.
    // After: SetValue on the BaseItem is called.
    item->SetValue(5, nullptr);
    

    如果我编辑 派生项 这样地:

    class DerivedItem : public BaseItem
    {
      public:
        virtual void SetValue(int first, int* second = nullptr)
        {
        };
    }
    

    这个 SetValue 派生项 被再次调用。

    1 回复  |  直到 1 年前
        1
  •  1
  •   M.M    1 年前

    函数重写基于参数及其类型,不考虑默认值。在改变之后, DerivedItem::SetValue 不再是的覆盖 BaseItem::SetValue ,它只是一个成员函数,它遮蔽了同名的基函数。

    您可以让编译器通过使用 override 关键字,无论何时您打算进行覆盖:

    class DerivedItem : public BaseItem
    {
        virtual void SetValue(int first) override
    

    如果函数实际上没有覆盖基类中的函数(而不是运行时行为中的静默更改),那么它将给出一个错误。


    要覆盖函数,您必须使派生类签名与基类匹配,正如您所发现的那样。

    在我看来,完全避免默认参数,并添加另一个函数重载以支持不同的参数集,这样更干净、更健壮。因此,基类将具有:

    virtual void SetValue(int first){ ... }
    virtual void SetValue(int first, int second){ ... }
    

    并且派生的可以覆盖一个或两个。这种方法还可以更好地处理调用SetValue的现有代码。