【问题标题】:overriden virtual function is not getting called被覆盖的虚函数没有被调用
【发布时间】:2010-02-23 11:10:28
【问题描述】:

更准确的代码版本是:

class SomeParam;
class IBase
{
public:
    virtual void Func(SomeParam* param = NULL)
    {
        cout << "Base func";
    }
};

class DerivedA : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedA func";
        IBase::Func();
    }
};

class DerivedB : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

//at somewhere else
void FuncCaller(IBase *instance1, IBase *instance2)
{
    IBase *i1 = instance1;
    IBase *i2 = instance2;
    i1->Func();
    i2->Func();
}

DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(a,b);

这给了我:
“基本功能”
“基础函数”

【问题讨论】:

  • 按预期工作。请检查您是否正在编译正确的文件。
  • 对我来说很好。你能发布你的实际代码吗?
  • 我试图用 Visual Studio 2005 编译它,我得到了预期的输出:DerivedA funcBase funcDerivedB funcBase func。这是完全相同的代码吗?
  • @Drakosha、@Poita_、@Patrick - 我确实编辑了代码以删除一些空格,但有可能我搞砸了 - 你们中有人可以在 Taz 发布的原始版本中检查它吗?跨度>
  • 只是一个旁注:我怀疑你称 'IBase' 'I' 是因为你认为它像一个接口,但一个接口应该只有纯虚拟方法。

标签: c++ inheritance function virtual


【解决方案1】:

看起来您提供了代码的简化版本以使其更具可读性,但您无意中过度简化了。

您的行为最可能的原因是:

  • FuncCaller() 中切片(详见 quamrana 的回答)
  • 错误的覆盖,比如让派生类函数const,而基类函数不是const

编辑:阅读编辑后的问题后,显然是第二个原因。您不是覆盖基类函数,而是使用新定义将其隐藏在派生类中。您需要在派生类中保持完全相同的签名(协方差在这里不适用,因为函数返回void)。在代码中,您需要执行以下任一操作:

class SomeParam;
class IBase
{
public:
    virtual void Func(SomeParam* param = NULL)
    {
        cout << "Base func";
    }
};

class DerivedA : public IBase
{
public:
    void Func(SomeParam* param = NULL)
    {
        //do some custom stuff
        cout << "DerivedA func";
        IBase::Func();
    }
};

class DerivedB : public IBase
{
public:
    void Func(SomeParam* param = NULL)
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

//at somewhere else
void FuncCaller(IBase *instance1, IBase *instance2)
{
    IBase *i1 = instance1;
    IBase *i2 = instance2;
    i1->Func();
    i2->Func();
}

DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(a,b);

class SomeParam;
class IBase
{
public:
    virtual void Func()
    {
        cout << "Base func";
    }
};

class DerivedA : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedA func";
        IBase::Func();
    }
};

class DerivedB : public IBase
{
public:
    void Func()
    {
        //do some custom stuff
        cout << "DerivedB func";
        IBase::Func();
    }
};

//at somewhere else
void FuncCaller(IBase *instance1, IBase *instance2)
{
    IBase *i1 = instance1;
    IBase *i2 = instance2;
    i1->Func();
    i2->Func();
}

DerivedA *a = new DerivedA;
DerivedB *b = new DerivedB;
FuncCaller(a,b);

【讨论】:

  • 正如 AndreyT 所说,定义参数的默认值并不是绝对必要的;但不在同一函数的所有覆盖中定义相同的默认值将是非常糟糕的做法。
【解决方案2】:

您的虚函数未被覆盖。

派生类中所谓的“虚拟”方法具有不同的签名。基类中的方法只有一个参数,而派生类中的方法没有参数。因此,派生类中的方法与基类方法完全无关。它们不会覆盖基类方法。这就是为什么总是调用基类方法的原因。

【讨论】:

    【解决方案3】:

    我已经尝试了您在 VS2008 上发布的代码的副本,它运行良好。

    我只能建议您的实际代码更像:

    void FuncCaller(IBase instance)
    {
        instance.Func();
    }
    
    void Funcs()
    {
    DerivedA *a = new DerivedA;
    DerivedB *b = new DerivedB;
    FuncCaller(*a);
    FuncCaller(*b);
    }
    

    FuncCaller 从派生实例中分割出基础部分。

    【讨论】:

      【解决方案4】:

      我找到了原因:
      被覆盖的虚函数也必须有一个默认参数,如 Base's.like:

      class DerivedB : public IBase
      {
      public:
          void Func(SomeParam* param=NULL)
          {
              //do some custom stuff
              cout << "DerivedB func";
              IBase::Func();
          }
      };
      

      谢谢大家的回答。

      【讨论】:

      • 他们不必专门定义 default 参数。他们确实需要一个参数,以便基本的Func 签名与派生的Func 签名相匹配。派生版本是否有默认参数根本不重要。
      • @AndreyT:是的,但不为所有参数定义相同的默认值将是一种糟糕的做法。
      猜你喜欢
      • 2013-09-21
      • 1970-01-01
      • 2020-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      • 1970-01-01
      相关资源
      最近更新 更多