Перегрузка виртуальной функции в дочернем классе - PullRequest
11 голосов
/ 11 января 2012

Я просто тестирую виртуальные ключевые слова и концепции наследования в 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 ()".

Ответы [ 6 ]

23 голосов
/ 11 января 2012

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

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

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

using cna_MO::print;

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

Хорошо прочитано:

В чем смысл, Предупреждение: Derived :: f (char) скрывает Base :: f (double)?

0 голосов
/ 11 января 2012

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

0 голосов
/ 11 января 2012

В идеале ваша печать, которая принимает int, должна иметь другое имя, но, учитывая, что вы хотите, чтобы обе функции назывались 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;     
      } 
 };  
0 голосов
/ 11 января 2012

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

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

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

0 голосов
/ 11 января 2012

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

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

0 голосов
/ 11 января 2012

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

в 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, вы, вероятно, можете предположить, что они ничего не передали.

Хитрость в том, что и родитель, и ребенок нуждаются в одинаковом методе сигнатуры, что означает одинаковый тип возвращаемого значения и один и тот же аргументтипы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...