Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.50/8: Рейтинг темы: голосов - 8, средняя оценка - 4.50
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36

Как сделать, чтобы производный класс наследовал все операторы от родительского класса и от родительского родительского

20.01.2021, 01:19. Показов 1890. Ответов 10

Студворк — интернет-сервис помощи студентам
Есть 1й базовый класс в кот. определён operator ++ (); //prefix
Есть производный от 1го, 2й класс в кот. дополнительно определён operator -- (); //prefix
Создаю 3й класс производный от 2го, в котором ещё определяю два оператора таких же но в postfix нотации
operator ++ (int); // postfix
и
operator -- (int); // postfix

Почему то от 1го ко 2му классу operator ++ (); //prefix нормально наследуется и работает, также, как
новый operator -- (); //prefix , а вот в 3м работают только вновь определённые операторы:
operator ++ (int); // postfix
и
operator -- (int); // postfix
НО при этом от первых 2х классов операторы operator ++ (); //prefix и operator -- (); //prefix компилятор принимать отказывается! Т.е. обе префиксные формы в 3м классе перестают опознаваться.
Как это поправить?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////
class Counter
{
protected: //NOTE: not private
    unsigned int count; //count
public:
    Counter() : count(0) //constructor, no args
    { }
    Counter(int c) : count(c) //constructor, one arg
    { }
    unsigned int get_count() const //return count
    {
        return count;
    }
    Counter operator ++ () //incr count (prefix)
    {
        return Counter(++count);
    }
};
////////////////////////////////////////////////////////////////
class CountDn : public Counter
{
public:
    CountDn() : Counter() //constructor, no args
    { }
    CountDn(int c) : Counter(c) //constructor, 1 arg
    { }
    CountDn operator -- () //decr count (prefix)
    {
        return CountDn(--count);
    }
};
////////////////////////////////////////////////////////////////
 
class CounterFL: public CountDn 
{
public:
    CounterFL(): CountDn()
    {                       }
 
    CounterFL(int c) : CountDn(c)
    {                            }
 
    CounterFL operator ++ (int) // increment postfix
    {
        return CounterFL(count++);
    }
 
    CounterFL operator -- (int) // decrement postfix
    {
        return CounterFL(count--);
    }
};
 
int main()
{
    CountDn c1; //class CountDn
    cout << "\nc1 = " << c1.get_count(); //display
    ++c1; ++c1; // работает
    cout << "\nc1 = " << c1.get_count(); //display
 
    --c1; // работает
    cout << "\nc1 = " << c1.get_count(); //display
 
    CounterFL cn1;
    CounterFL cn2(95);
    cout << "\ncn1 = " << cn1.get_count(); //display
    cout << "\ncn2 = " << cn2.get_count(); //display
 
    
    --cn1; // не работает!!!
    ++cn1; // не работает!!!
 
    return 0;
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
20.01.2021, 01:19
Ответы с готовыми решениями:

Доступ к методу родительского класса из метода свойства родительского класса
Не знаю правильно ли написал тему, ну суть такая, есть класс который описывает допустим шарик, а есть класс который описывает массив этих...

Как сделать, чтобы, при закрытии родительского, pop-up окно тоже закрывалось?
открываю через &lt;img scr='image.gif' onLoad='window.open()'&gt;новое pop-up окно. как сделать, чтобы, при закрытии родительского, pop-up окно...

Можно ли получить текущий класс объекта в статическом методе родительского класса?
Здравствуйте, можно ли получить текущий класс объекта в статическом методе родительского класса?

10
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
20.01.2021, 03:31
Цитата Сообщение от realalexandro Посмотреть сообщение
Как сделать, чтобы производным классом наследовались все операторы от родительского кл и от родительского родительского
Они и так наследуются.

Цитата Сообщение от realalexandro Посмотреть сообщение
НО при этом от первых 2х классов операторы operator ++ (); //prefix и operator -- (); //prefix компилятор принимать отказывается!
Это явление называется сокрытием имен.

Цитата Сообщение от realalexandro Посмотреть сообщение
Как это поправить?
C++
1
2
3
4
5
6
7
class CounterFL: public CountDn 
{
public:
  ...
  using CountDn::operator ++;
  using CountDn::operator --;
  ...
1
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
20.01.2021, 06:39  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Это явление называется сокрытием имен.
Сообщение от realalexandro
Как это поправить?
C++
1
2
3
4
5
6
class CounterFL: public CountDn 
{
public:
  ...
  using CountDn::operator ++;
  using CountDn::operator --;
  ...
А чем обусловлено такое сокрытие имён и как оно работает? Просто На 1м уровне наследования от Counter до CountDn
operator ++() в CountDn и так доступен объектам последнего без директивы using и без вставки scope resolution Counter::operator++(переменная) перед использованием оператора. Почему же в CounterFl она уже необходима? Ведь 2 раннее определённых оператора префиксной формы, по этой же логике должны быть унаследованы от CountDn и доступны в CounterFl?

М.Б. есть какой то другой способ? Поясню. В главе по наследованию классов из книги, в кот. была эта задача (книга Лафоре) не было ни одного примера с using, и эта директива даже не упоминалась (кроме using namespace std).
Были только вызовы родительских функций-членов через '::' scope resolution в определённых ситуациях в методах объектов производного класса. Поэтому догадаться о таком механизме "передачи" родительских операторов в производный класс, как [using ...] из пройденного материала совершенно не возможно. Должен быть способ без using... либо задача не согласуется с теоретическим материалом т.е. автором был пропущен кусок изложения.

Тогда технически, если для постфиксной формы, инструкцию правильно писать так: using ИмяКласса::operator ++(int); ?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
20.01.2021, 07:53
Цитата Сообщение от realalexandro Посмотреть сообщение
Просто На 1м уровне наследования от Counter до CountDn operator ++() в CountDn и так доступен объектам последнего
Не играет роли какой уровень наследования. У вас в этом случае просто нет сокрытия имен, потому что нет одноименных функций-членов. В Counter нет оператора--, поэтому объявленный в CountDn оператор-- ничего не скрывает. Теперь в CountDn есть операторы ++ и --, а в CounterFL объявляются соответствующие одноименные (постфиксные) операторы. Т.к. они находятся по отношению к CountDn на другом уровне видимости, то происходит сокрытие их префиксных вариантов. Механизм точно такой же, как вот тут:
C++
1
2
3
4
5
6
int a; //1
int main() {
   int a; //2
 
   a = 10; // 2 скрывает 1 
}
это же поведение вас не удивляет, значит и в вашем случае не должно.

Чтобы сокрытия не происходило, а происходила перегрузка, надо префиксные формы "добавить" на тот же уровень видимости, где находятся постфиксные. Этим как раз и занимается using в данном случае.

Цитата Сообщение от realalexandro Посмотреть сообщение
Тогда технически, если для постфиксной формы, инструкцию правильно писать так: using ИмяКласса::operator ++(int); ?
Нет. Указывается только имя функции.


Цитата Сообщение от realalexandro Посмотреть сообщение
эта задача (книга Лафоре)
Это потому, что книга Лафоре плохая с точки зрения технической достоверности и полноты информации. К тому же она очень старая. Эта задача и ошибки подачи материала для нее десятки раз обсуждались на этом форуме.
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
20.01.2021, 09:02
Лучший ответ Сообщение было отмечено realalexandro как решение

Решение

Цитата Сообщение от realalexandro Посмотреть сообщение
А чем обусловлено такое сокрытие имён и как оно работает?
Для классов: если в классе есть член по имени foo, то он "скрывает" все унаследованные члены по имени foo. Это означает, что унаследованные члены невозможно будет найти по неквалифицированному имени foo. Неквалифицированный поиск имени foo в области видимости класса-наследника будет видеть только его собственные члены foo. А чтобы получить доступ к "скрытым" унаследованным членам придется указывать их квалифицированные имена class::foo.

Цитата Сообщение от realalexandro Посмотреть сообщение
Просто На 1м уровне наследования от Counter до CountDn
operator ++() в CountDn и так доступен объектам последнего без директивы using и без вставки scope resolution Counter::operator++(переменная) перед использованием оператора.
Потому что в классе CountDn нет метода по имени operator ++. Поэтому сокрытия не происходит и унаследованный Counter::operator ++ остается видимым и в классе CountDn.

Цитата Сообщение от realalexandro Посмотреть сообщение
Ведь 2 раннее определённых оператора префиксной формы, по этой же логике должны быть унаследованы от CountDn и доступны в CounterFl?
Они унаследованы и доступны. Но не через неквалифицированное имя, ибо они скрыты в CounterFl его собственными операторами по имени operator ++ и operator --.

Цитата Сообщение от realalexandro Посмотреть сообщение
есть какой то другой способ?
Переписать эти операторы целиком в CounterFl (например, с вызовом унаследованного внутри через квалифицированное имя), что, однако, будет еще более громоздко, чем using.

Цитата Сообщение от realalexandro Посмотреть сообщение
Тогда технически, если для постфиксной формы, инструкцию правильно писать так: using ИмяКласса::operator ++(int); ?
Нет. У using нет возможности выбора конкретного перегруженного метода. Он работает только огульно: вы указываете имя сущности и "раскрываете" все вариации этой сущности. Если это имя метода, то тем самым вы "раскрываете" все скрытые перегрузки этого метода. Если при этом в вашем классе уже есть явно объявленный метод с аналогичной сигнатурой, то "победит" он, то есть из-за using конфликта не возникнет.

Хотите "раскрывать" скрытые методы индивидуально/выборочно - просто перереализуйте их в классе-наследнике явно.

Цитата Сообщение от realalexandro Посмотреть сообщение
В главе по наследованию классов из книги, в кот. была эта задача (книга Лафоре) не было ни одного примера с using, и эта директива даже не упоминалась
В такой ситуации перереализация скрытого метода "впишется" в порядок изложения материала книгой.
2
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
20.01.2021, 09:38  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Это потому, что книга Лафоре плохая с точки зрения технической достоверности и полноты информации. К тому же она очень старая. Эта задача и ошибки подачи материала для нее десятки раз обсуждались на этом форуме.
Спасибо за дельное объяснение!
А какую нибудь хорошую более современную книгу можете посоветовать?!

Добавлено через 13 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет. У using нет возможности выбора конкретного перегруженного метода. Он работает только огульно: вы указываете имя сущности и "раскрываете" все вариации этой сущности. Если это имя метода, то тем самым вы "раскрываете" все скрытые перегрузки этого метода. Если при этом в вашем классе уже есть явно объявленный метод с аналогичной сигнатурой, то "победит" он, то есть из-за using конфликта не возникнет.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class CounterFL: public CountDn 
{
public:
    CounterFL(): CountDn()
    {                       }
 
    CounterFL(int c) : CountDn(c)
    {                            }
[B]
    CounterFL operator ++ (int) // increment postfix
    {
        return CounterFL(count++);
    }
 
    CounterFL operator -- (int) // decrement postfix
    {
        return CounterFL(count--);
    }
    using CountDn:: operator++;
    using CountDn:: operator--;
[/B]
};
 
...
++cn1; 
--cn1;
Спасибо за подробное разъяснение!
Означает ли Ваша последняя фраза про аналогичную сигнатуру, что в приведённом коде инструкции
++cn1; и
--cn1;

на самом деле задействуют ПОСТфиксную форму, поскольку она заменяет в классе CounterFl те 2 префиксные, которые
мы снова "де-маскируем" с помощью using? Или их сигнатура не считается аналогичной префиксным из первых 2х классов?
0
20.01.2021, 09:43

Не по теме:

Цитата Сообщение от realalexandro Посмотреть сообщение
А какую нибудь хорошую более современную книгу можете посоветовать?!
Ответил в соседней теме, которая про задачи из Лафоре.

0
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
20.01.2021, 09:43  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Хотите "раскрывать" скрытые методы индивидуально/выборочно - просто перереализуйте их в классе-наследнике явно.
В данном случае тогда не будет смысла в механизме наследования классов. Проще сразу в род. классе все операторы определить
Разве что тренировка самого объявления наследования с такими "костылями" в виде переопределения тех же операторов, которые ведут себя аналогично операторам род. класса.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
20.01.2021, 10:16
Цитата Сообщение от realalexandro Посмотреть сообщение
В данном случае тогда не будет смысла в механизме наследования классов. Проще сразу в род. классе все операторы определить
У вас может не быть возможности все операторы определить в родительском классе просто потому, что необходимые для их реализации сопутствующие дополнительные элементы будут появляться только в наследниках. Это в вашем случае ничего дополнительного не нужно, но ваш случай - лишь частный непоказательный пример.
0
0 / 0 / 0
Регистрация: 25.07.2020
Сообщений: 36
20.01.2021, 10:20  [ТС]
TheCalligrapher, ну всё я усёк!
А на вопрос выше ответьте, пожалуйста.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12937 / 6804 / 1821
Регистрация: 18.10.2014
Сообщений: 17,218
20.01.2021, 11:23
Цитата Сообщение от realalexandro Посмотреть сообщение
Означает ли Ваша последняя фраза про аналогичную сигнатуру, что в приведённом коде инструкции
++cn1; и
--cn1;
на самом деле задействуют ПОСТфиксную форму, поскольку она заменяет в классе CounterFl те 2 префиксные, которые
мы снова "де-маскируем" с помощью using? Или их сигнатура не считается аналогичной префиксным из первых 2х классов?
Нет, не означает. Постфиксный и префиксный операторы имеют разные сигнатуры. Объявление постфиксного оператора может скрыть объявление префиксного, но никак не может заменить его. Для ++cn1 и --cn1 всегда вызывается именно префиксная форма. Если он по какой-то причине недоступна, то будет ошибка компиляции. Тихого вызова постфиксной формы в таких выражениях не будет никогда.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
20.01.2021, 11:23
Помогаю со студенческими работами здесь

Как узнать поле родительского класса?
Производного класса-ошибся.(не знаю как изменить тему) Есть: QHash&lt;QMediaObject*,myItem*&gt;* link; В QMediaObject записываю...

Как вызвать функцию родительского класса?
#include &lt;iostream&gt; using namespace std; class foo{ void somefunc(); public: int i; };

Как вызвать метод родительского класса;
Собственно вопрос; Есть класс a и b; Класс b унаследован от класса a; И как теперь из класса b вызвать функцию класса a;

Как узнать имя родительского класса?
Товарищи помогите, не могу нарыть. Как узнать и вывести в консоль имя родительского класса ( и вообще имена классов ) ? типо this.class (...

Как использовать явный конструктор родительского класса?
Привет :) Вот код, строчка 43. Как использовать конструктор типа A(int), в классе C? Компилятор выдаёт ошибку (Error:...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru