Производный класс не видит перегруженную операцию базового класса

IvanInanovich

Подскажите пожалуйста, почему производный класс, а именно его объект не видит перегруженную операцию, в данном случае это префиксные операции (++,--). Без них программа запускается. В начале базовый класс, за ним производный,а у производного есть свой производный. Вот код:
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class Counter
   {
   protected:
      unsigned int count;
   public:
      Counter() : count(0)
         {  }
      Counter(int c) : count(c)
         {  }
      unsigned int get_count() const
         { return count; }
      Counter operator++()
         { return Counter(++count); }
   };
////////////////////////////////////////////////////////////////
class CountDn : public Counter
   {
   public:
      CountDn() : Counter()
         { }
      CountDn(int c) : Counter(c)
         { }
      CountDn operator--()
         { return CountDn(--count); }
   };
////////////////////////////////////////////////////////////////
 
 
class C3 : public CountDn
{
public:
    C3():CountDn(){}
    C3(int i):CountDn(i){}
 
 
    C3 operator--(int)
    {
       return C3(count--);
    }
    C3 operator++(int)
    {
        return C3(count++);
    }
};
////////////////////////////////////////////////////////
int main()
   {
       C3 c1(10);
 
       c1++;
       c1--;
       ++c1;
       --c1;
       c1++;
 
   cout << c1.get_count() << endl;
   return 0;
   }
8 ответов

IvanInanovich

Вы в производном уже перегрузили (++,--), правда с другим числом аргументов, так чего же вы хотите? Данный код тоже не будет компилироваться:
#include <iostream>
 
using namespace std;
 
class A
{
   public:
      void who()
      {
         cout << "A" << endl;
      }
};
 
class B: public A
{
   public:
      void who(int)
      {
         cout << "B" << endl;
      }
};
 
int main()
{
   B b;
 
   b.who(); // Ошибка. Сработает только если явно задать b.A::who()
 
   return 0;
}


IvanInanovich

Вы в производном уже перегрузили (++,--), правда с другим числом аргументов, так чего же вы хотите?
В книге Р. Лафоре ООП, пишется что компилятор различает префиксную и постфиксную форму перегрузки по аргументу int. Перед этим было задание в котором была перегрузка операции [ ] (квадратных скобок). Ситуация примерно такая же была, но программа запускалась не смотря на то, что перегрузка была в первом классе, а потомок был как данной ситуации 3м классом по счету. Т.е. А потомок Б, у Б потомок Г. Явно я не указывал "скобки". Возможно чего-то не понимаю. Но в задании четко говорится сделайте потомка с префиксом инкриминации.Точнее не префиксной, а постфиксной. В итоге префиксная не работает. Вот задание.


IvanInanovich

http://www.parashift.com/c++-faq-lite/hiding-rule.html
Благодарю за ссылку. Но увы, прочитать я то смогу, а уловить всю логику и перевести нормально - вряд ли. Можно ли в 2х словах?


IvanInanovich

IvanInanovich, перегружая метод в производном классе вы скрываете метод определённый в базовом. Для того чтобы сделать этот метод видимым для производного класса нужно использовать ключевое слово using. В вашем случае
class C3 : public CountDn
{
public:
    //...
    using CountDn::operator ++;
    using CountDn::operator --;
};


IvanInanovich

IvanInanovich, перегружая метод в производном классе вы скрываете метод определённый в базовом. Для того чтобы сделать этот метод видимым для производного класса нужно использовать ключевое слово using. В вашем случае
class C3 : public CountDn
{
public:
    //...
    using CountDn::operator ++;
    using CountDn::operator --;
};
Работает, спасибо большое. Теперь все понятно)) Единственное не понял почему в таком случае не ставятся круглые скобки в конце перегрузки оператора. Я было попробовал с ними, но выбило ошибку. Как быть в ситуации если нужно будет операция с аргументом? К примеру operator++(int).


IvanInanovich

Теперь все понятно)) Единственное не понял почему в таком случае не ставятся круглые скобки в конце перегрузки оператора.
Судя по всему, не очень Допустим, есть следующая иерархия классов
class A
{
public:
    void f();
    void f(int);
    void f(int, int);
};
 
class B : public A
{
public:
    // перекрываем метод с именем f(если не иcпользовать using, то у класса B будет своя версия метода f...
    //... к тем его перегрузкам, что находятся в А можно будет обратиться только, если явно указать их область видимости...
    //... например, имя_объект.A::f())
    void f(int, int);
    void f(int, int, int);
};
Используя ключевое слово using можно явно указать, что класс потомок, помимо уже определённых в нём методов, будет использовать реализции методов определённых с тем же именем в указаном классе предке
class B : public A
{
public:
    void f(int, int);
    void f(int, int, int);
    
    // использовать f из А без указания области видимости
    // при этом из A будут использоваться только f() и f(int) потому как метод f(int, int) переопределён)
    using A::f; 
};
Т.е. это не включение какой-то отдельной перегрузки класса предка, а указание использовать все не переопределённые в классе потомке реализации.
Как быть в ситуации если нужно будет операция с аргументом? К примеру operator++(int).
Если в случае перекрытия нужно использовать реализацию отдельного метода класса предка, то можно просто вызвать необходимый метод явно
class B : public A
{
public:
    void f(int x)
    {
        A::f(x);
    }
//...
};


IvanInanovich

Огромное Вам спасибо! Теперь точно все понял))) Удивительно что в книге об этом ничего не говорилось.