Перегрузка виртуальной функции в дочернем классе

Я просто тестирую с помощью концепций виртуального ключевого слова и наследования в С++. Я написал небольшую программу:

#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()".

Ответ 1

Как только вы перегрузите функцию из базового класса в классе Derived, все функции с тем же именем в базовом классе будут скрыты в классе Derived.

После добавления функции cna_bsc::print(int a) в производный класс функция cna_MO::::print() больше не будет видна пользователям класса Derived. Это называется функцией скрытия.

Решение: Чтобы сделать скрытую функцию видимой в производном классе, вам нужно добавить:

using cna_MO::print;

в разделе public вашего производного класса cna_bsc.

Хорошее Чтение:

Что означает, Warning: Derived:: f (char) скрывает Base:: f (double)?

Ответ 2

Это потому, что функция печати в дочернем классе принимает параметр, а оригинал - нет.

в cna_MO (родительский класс):

virtual void print()

в cna_bsc (дочерний класс):

void print(int a)

В основном дочерняя печать не должна принимать аргумент int:

void print()

EDIT:

Может быть, лучше всего было бы сделать передачу 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)

поэтому, если вы, возможно, предположите, что == -1, они ничего не пропускали.

Фокус в том, что и родительскому, и дочернему нужно один и тот же метод siganture, что означает тот же тип возврата и те же типы аргументов.

Ответ 3

Если у вас есть функция с таким же именем и разными параметрами в производном классе, как у базового класса, то эта функция будет скрыта. Вы можете найти более подробную информацию здесь..

Вы можете вызвать конкретную скрытую функцию, вызвав как Base::hiddenFun();

Ответ 4

Это не сработает, поскольку с учетом cna_MO * вы можете видеть во время компиляции, что заостренный объект не обязательно (обязательно) имеет перегрузку int. Если он фактически указал на объект базового класса, _mo->print(5); действительно нечего было бы вызывать. Также может быть бесконечное число (еще не реализовано) производных классов, которым не нужно поддерживать этот вызов.

  • Каждый производный класс должен иметь print(int) - объявить его в базовом классе.

  • Каждый производный класс не должен иметь print(int) - cna_Mo работает только с cna_bsc, поэтому член должен быть cna_bsc* _mo.

Ответ 5

В идеале ваша печать, которая принимает int, должна иметь другое имя, но если вы хотите, чтобы обе функции назывались печатью, вы должны сделать их не виртуальными и заставить их вызывать защищенные виртуальные функции.

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

Ответ 6

Если вы ДЕЙСТВИТЕЛЬНО ДОЛЖНЫ делать это так, то есть иметь указатель на один класс и инициализировать как производный класс, нет выбора, кроме как всегда указывать указатель на правильный тип при его использовании. В этом случае ((cna_bsc*)_mo)->print(5);