【问题标题】:Overloading a virtual function in a child class在子类中重载虚函数
【发布时间】:2012-02-07 15:54:17
【问题描述】:

我只是在 C++ 中使用虚拟关键字和继承概念进行测试。 我写了一个小程序:

#include<stdio.h>
#include<iostream>

using namespace std;

class cna_MO
{
  public:
    virtual void print()
    {
        cout << "cna_MO" << endl;
    }
};

class cna_bsc:public cna_MO
{
  public:
    void print()
    {
        cna_MO::print();
    }

    void print(int a)
    {
        cout << "cna_BSC" << endl;
    }
};

class cna_Mo
{
    cna_MO *_mo;

  public:
    cna_Mo()
    {
        _mo = new cna_bsc;
    }

    virtual void print(int a)
    {
        cout << "cna_Mo with arg" << endl;
        _mo->print(5);
    }

    virtual void print()
    {
        cout << "cna_Mo" << endl;
        _mo->print();
    }
};

int main()
{
    cna_Mo valid_mo;
    cout << "old case is started" << endl;
    valid_mo.print();
    cout << "new case is started" << endl;
    valid_mo.print(5);
    return 0;
}

我在这里所做的是我在子类的父类中重载了一个虚函数!这不是正确的做法吗?

我收到如下编译错误:

“temp10.cc”,第 45 行:错误:调用“cna_MO::print()”时参数过多。

【问题讨论】:

标签: c++ inheritance virtual


【解决方案1】:

一旦你从派生类中的基类重载一个函数,所有基类中同名的函数都会隐藏在派生类中。

将函数cna_bsc::print(int a) 添加到派生类后,派生类的用户将不再看到函数cna_MO::::print()。这称为函数隐藏。

解决方案: 为了使隐藏函数在派生类中可见,您需要添加:

using cna_MO::print;

在派生类cna_bscpublic 部分中。

好读:

What's the meaning of, Warning: Derived::f(char) hides Base::f(double)?

【讨论】:

  • 我明白了你的意思,但我还有一个问题...编辑了问题。请立即检查问题。即使在进行更改后,我也遇到了太多的 agrs 错误。
  • 当您调用 _mo-&gt;print(5); 时,错误出现在 cna_MO::print() 中,请注意 _mo 的类型为 cna_MO *cna_MO 类没有 print() 函数,该函数采用单个参数和因此错误。您感到困惑的原因是混淆了非不同的类名,永远不要使用这样的命名约定
【解决方案2】:

如果派生类中的函数与基类具有相同的名称和不同的参数,那么该函数将被隐藏。你可以找到更多信息here..

可以通过Base::hiddenFun();这样的方式调用具体的隐藏函数

【讨论】:

    【解决方案3】:

    这是因为子类中的打印函数带参数,而原来没有。

    在 cna_MO(父类)中:

    virtual void print()
    

    在 cna_bsc(子类)中:

    void print(int a)
    

    基本上孩子的 print 不应该带一个 int 参数:

    void print()
    

    编辑:

    也许最好的办法是让 int 可选?

    例如:

    在 cna_MO(父类)中:

    virtual void print(int a=-1) {
        if (a == -1) {
            // Do something for default param
        } else {
            cout << a;
        }
    }
    

    在 cna_bsc(子类)中:

    void print(int a=-1)
    

    所以如果 a == -1 你可以假设,他们没有通过任何东西。

    诀窍是父母和孩子都需要相同的方法签名,这意味着相同的返回类型和相同的参数类型。

    【讨论】:

    • 现在是因为你试图在该行传递一个 int 来调用它:valid_mo.print(5);
    【解决方案4】:

    理想情况下,采用 int 的 print 应该具有不同的名称,但如果您希望将这两个函数都称为 print,则应该将它们都设为非虚拟函数并让它们调用受保护的虚拟函数。

    class cna_MO 
    {   
        public:     
         void print() { doPrint(); }
    
        protected:
         virtual void doPrint()
          {         cout << "cna_MO" << endl;     
          } 
    };  
    
    
    class cna_bsc:public cna_MO 
    {   
        protected:     
           virtual void doPrint()  
                      // although with implementation no need to override it
           {         
                cna_MO::print();     
           } 
    
        public:
         void print(int a)    
          {
              doPrintInt( a );
          }
    
        protected:
          virtual void doPrintInt( int )
          {
            cout << "cna_BSC" << endl;     
          } 
     };  
    

    【讨论】:

      【解决方案5】:

      如果你真的必须这样做,即有一个指向一个类的指针并初始化为派生类,那么别无选择,只能在使用它时始终将指针转换为正确的类型。在这种情况下,((cna_bsc*)_mo)-&gt;print(5);

      【讨论】:

        【解决方案6】:

        这是行不通的,因为给定cna_MO *,您可以在编译时看到指向的对象(必然)没有 int 重载。如果它实际上指向一个基类对象,_mo-&gt;print(5); 将真的没有什么可调用的。此外,可能有无数(尚未实现)派生类不必支持此调用。

        1. 每个派生类都必须有print(int) - 在基类中声明它。

        2. 每个派生类不必有print(int) - cna_Mo 仅适用于cna_bsc,因此成员应为cna_bsc* _mo

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-02-08
          • 2013-06-11
          • 2017-08-06
          • 2023-01-07
          • 2020-07-16
          • 1970-01-01
          相关资源
          最近更新 更多