Overloading a virtual function in a child class

2019-02-16 14:51发布

问题:

I am just testing with virtual keyword and inheritance concepts in c++. I have written a small program:

#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;
}

What I have done here is I have overloaded a virtual function in parent class in child class! Is this not the right thing to do?

I am getting the compilation errors as below:

"temp10.cc", line 45: Error: Too many arguments in call to "cna_MO::print()".

回答1:

Once you overload a function from Base class in Derived class all functions with the same name in the Base class get hidden in Derived class.

Once you added the function cna_bsc::print(int a) to your derived class the function cna_MO::::print() is no longer visible to users of the Derived class. This is known as function hiding.

Solution: In order to make the hidden function visible in derived class, You need to add:

using cna_MO::print;

in the public section of your derived class cna_bsc.

Good Read:

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



回答2:

When you have a function with same name and different parameters in the derived class as that of the base class, then that function will be hidden. You can find more info here..

You can call the specific hidden function by calling like Base::hiddenFun();



回答3:

It's because the print function in the child class takes a parameter and the original doesn't.

in cna_MO (parent class):

virtual void print()

in cna_bsc (child class):

void print(int a)

Basically the child's print should not take an int argument:

void print()

EDIT:

Maybe the best would be to make passing the int optional ?

eg:

in cna_MO (parent class):

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

in cna_bsc (child class):

void print(int a=-1)

so if a == -1 you can probably assume, they didn't pass anything.

The trick is that both the parent and child need the same method siganture, meaning same return type and the same argument types.



回答4:

Ideally your print that takes an int should have a different name but given you want both functions to be called print, you should make them both non-virtual and make them call protected virtual functions.

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:

If you REALLY MUST do it like this, i.e. have a pointer to one class and initialise as a derived class, there's no choice but to always cast the pointer to the correct type when using it. In this case, ((cna_bsc*)_mo)->print(5);



回答6:

That can't work because given a cna_MO *, you can see at compile-time that the pointed object does not (necessarily) have the int overload. If it actually pointed to a base-class object, _mo->print(5); would really have nothing to call. Also there can be an infinite number of (not yet implemented) derived classes that don't have to support this call.

  1. Every derived class must have print(int) - declare it in the base class.

  2. Every derived class need not have print(int) - cna_Mo only works with cna_bsc, so the member should be cna_bsc* _mo.