Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.51/75: Рейтинг темы: голосов - 75, средняя оценка - 4.51
6 / 6 / 5
Регистрация: 15.05.2014
Сообщений: 104

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

11.08.2015, 17:35. Показов 15664. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Продолжая тему наследования, в которой было выяснено, что можно вернуть в область видимости часть методов, которые потерялись при наследовании при помощи различных методов.

Возникает аналогичный вопрос, но наоборот. Предположим у нас есть некоторая иерархия наследования:
C++
1
2
3
4
5
6
7
8
9
10
11
12
class Parent
{
public:
    void foo() { std::cout << "parent foo " << std::endl; }
    void bar() { std::cout << "parent bar " << std::endl; }
};
 
class Child : public Parent
{
public:
    void fun(int num) { std::cout << "child fun " << std::endl; }
};
И мы хотим, чтобы в дочернем классе в области видимости находились не все методы базового класса:

C++
1
2
3
4
Child child;
child.foo();
child.bar();
child.fun();
Как в этом случае можно скрыть часть методов базового класса из области видимости, возможно, оставив доступ через обращение к родительскому классу. Например, мы хотим скрыть метод bar:

C++
1
2
3
4
Child child;
child.foo();
child.Parent::bar();
child.fun();

Не по теме:

Применение: Например базовый класс содержит большое число методов, а в некотором наследнгике нужно только пару штук и мы не хотим, чтобы весь талмут методов вылазил в IDE как подсказка. Понимаю, что если класс с большим числом методов, то скорее всего он спроектирован не правильно и его можно разбить на несколько небольших классов, но вопрос не в этом.

0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
11.08.2015, 17:35
Ответы с готовыми решениями:

Определить глубину наследования до базового класса
На вход подается синтаксически верная программа на C++. искать буду примерно следующее class Name ]{...}; поиск делаю по ключевому...

Запрет наследования члена базового класса
Подскажите, как запретить? class A { public: int a; }; class B : A {

Вызов методов производного класса из базового
Возможно ли, чтобы class A { void f1() { f2();//если вызвано из B, то вызывается B::f2(), а не A::f2() } void f2(){} }

17
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
11.08.2015, 17:45
Могу ошибаться, поскольку вопрос наследования начал изучать недавно. Но, кажется, так (три разных способа):
  1. переместить Parent::bar(); в private в классе-родителе.
  2. создать функцию-член с таким же именем в Child (то есть, Child::bar(); ) и тогда она скроет одноимённую функцию-член в родителе.
  3. поместить Parent::bar() в неймспейс.
1
6 / 6 / 5
Регистрация: 15.05.2014
Сообщений: 104
11.08.2015, 18:00  [ТС]
Цитата Сообщение от gru74ik Посмотреть сообщение
Но, кажется, так (три разных способа):
1. переместить Parent::bar(); в private в классе-родителе.
2. создать функцию-член с таким же именем в Child (то есть, Child::bar(); ) и тогда она скроет одноимённую функцию-член в родителе.
3. поместить Parent::bar() в неймспейс.
Поправьте, если не верно:
1. А если базовый класс где-то используется независимо от дочерних, или другим дочерним все таки нужен доступ, то мы потеряем доступ к функции-члену базового класса.
2. В этом случае в области видимости будет одноименная функция, но уже от дочернего класса.
3. В этом случае прийдется переписывать код, зависящий от Parent в соответствии с новым namespace, либо использовать using.

Жду предложений, лишенных этих "недостатков".

Добавлено через 9 минут
Не получается заключить один метод в namespace.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Parent
{
public:
    void foo() { std::cout << "parent foo " << std::endl; }
    namespace ok {
        void bar() { std::cout << "parent bar " << std::endl; }
    }
};
 
class Child : public Parent
{
public:
    void fun() { std::cout << "child fun " << std::endl; }
};
 
int main()
{
    Child child;
    child.foo();
    //child.ok::bar();
    child.fun();
}


Как это сделать можно сделать правильно?
0
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
11.08.2015, 18:04
Цитата Сообщение от kquick Посмотреть сообщение
Жду предложений, лишенных этих "недостатков".
Объявить эту функцию другом (в базовом классе). Для тех потомков, для которых эта функция будет нужна, использовать явное приведение типа к базовому классу. Для "лишенцев" (тем, кому про эту функцию знать не надо) она будет недоступна.
P.S. В потомках всё-таки придётся править код - переделывать функцию-член в дружественную и добавлять приведение типа.
1
 Аватар для Хулиган
88 / 83 / 21
Регистрация: 08.08.2012
Сообщений: 737
11.08.2015, 18:06
Методы которые могут не понадобиться можно сделать чисто виртуальными
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class A
{
public:
    virtual void func() = 0;
};
 
class B : public A
{    
};
 
template<typename T>
void test(T& obj)
{
    obj.func();
}
 
int main()
{
    B b;
    test(b);
}
2
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
11.08.2015, 18:08
Лучший ответ Сообщение было отмечено kquick как решение

Решение

Цитата Сообщение от kquick Посмотреть сообщение
Как в этом случае можно скрыть часть методов базового класса из области видимости
Из области видимости никак. Можно лишь обеспечить недоступность.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A
{
    void foo() {}
};
 
struct B: A
{
private:
    using A::foo;
};
 
int main()
{
    B b;
    b.foo(); // fail
    b.A::foo(); // ok
}
4
6 / 6 / 5
Регистрация: 15.05.2014
Сообщений: 104
11.08.2015, 18:16  [ТС]
Цитата Сообщение от Хулиган Посмотреть сообщение
можно сделать чисто виртуальными
Тоже неплохой способ. Однако, если нам нужен неоторый функционал, в некотором другом базовом классе, наседуемом от базового класса с чисто виртуальными функциями, то нам прийдется определить эти функции. И в этом случае, при наследовании от нового класса вылезет опять та же самая проблема. А если сделать 2 разных ветви наследования. Одна - с нужными методами, другая без них, то получим дублирование кода в базовых классах.

Цитата Сообщение от ct0r Посмотреть сообщение
Можно лишь обеспечить недоступность.
Как защита от дурака тоже неплохо, спасибо.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
11.08.2015, 18:19
Лучший ответ Сообщение было отмечено kquick как решение

Решение

Цитата Сообщение от kquick Посмотреть сообщение
Например, мы хотим скрыть метод bar:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Parent
{
public:
    void foo() { std::cout << "parent foo " << std::endl; }
    void bar() { std::cout << "parent bar " << std::endl; }
};
 
class Child : public Parent
{
    using Parent::bar; // <--- объявляем, что метод Bar
     // в наследнике располагается в приватной секции
public:
    void fun(int num) { std::cout << "child fun " << std::endl; }
};
3
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
11.08.2015, 18:23
У hoggy самое простое и элегантное решение получилось.
0
 Аватар для Martein
704 / 109 / 21
Регистрация: 22.06.2014
Сообщений: 241
11.08.2015, 18:24
Лучший ответ Сообщение было отмечено kquick как решение

Решение

Если в программе приходится прибегать к таким манипуляциям, то скорее всего у нас имеется серьёзная архитектурная ошибка, так как мы нарушаем базовые принципы ООП, а конкретно то, что производный класс перестаёт быть частным случаем базового класса. Выходит, что мы не можем пользоваться производным классом так же, как и базовым (передавать в функции по ссылке/указателю на его базовый класс, например). Исходя из этого, можно сказать, что нам следует отказаться от наследования в пользу агрегации, далее вывесить нужные методы из "базового" класса наружу через интерфейс нашего "производного" класса, а если потребуется преобразовать наш результирующий тип к "базовому", то определить операцию преобразования типа. В итоге получаем:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Parent
{
public:
    void foo() { std::cout << "parent foo " << std::endl; }
    void bar() { std::cout << "parent bar " << std::endl; }
};
 
class Child
{
public:
    void fun(int num) { std::cout << "child fun " << std::endl; }
    void foo() { m_parent.foo(); }
    void bar() { m_parent.bar(); }
    operator Parent() { return m_parent; }
private:
    Parent m_parent;
};
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
11.08.2015, 18:37
Цитата Сообщение от Martein Посмотреть сообщение
Исходя из этого, можно сказать, что нам следует отказаться от наследования в пользу агрегации
ага, и получить ровно все тоже самое,
но ценой большего количества кода.

отличный способ на ровном месте усложнять себе жизнь.

Добавлено через 1 минуту
Цитата Сообщение от gru74ik Посмотреть сообщение
У hoggy самое простое и элегантное решение получилось.

Не по теме:

когда я его писал, я ещё не видел #6

1
Игогошка!
 Аватар для ct0r
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
11.08.2015, 18:42
Кстати это все круто, но к visibility имеет отношение так себе.

Member access does not affect visibility: names of private and privately-inherited members are visible and considered by overload resolution, implicit conversions to inaccessible base classes are still considered, etc. Member access check is the last step after any given language construct is interpreted. The intent of this rule is that replacing any private with public never alters the behavior of the program.
2
6 / 6 / 5
Регистрация: 15.05.2014
Сообщений: 104
11.08.2015, 18:45  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
отличный способ на ровном месте усложнять себе жизнь.
В некоторых случая может помочь. Например от базового класса наследуются классы без ограничений. И есть некоторый "наследник", который не должен показывать методы базового класса. Для него можно применить этот способ. Но, в целом, на счет увеличения кода с вами согласен. Кроме того, это может потребовать постоянных модификаций такого наследника в случае расширения функционала базового класса. Плюс ко всему это уже не будет наследником в привычном смысле этого слова.

Кликните здесь для просмотра всего текста
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
#include <iostream>
 
class Parent
{
public:
    void foo() { std::cout << "parent foo " << std::endl; }
    void bar() { std::cout << "parent bar " << std::endl; }
};
 
class Child : public Parent
{
public:
    void fun() { std::cout << "Child fun " << std::endl; }
};
 
class SomeChild
{
public:
    void fun() { std::cout << "SomeChildfun " << std::endl; }
    void foo() { m_parent.foo(); }
private:
    Parent m_parent;
};
 
 
int main()
{
    Child child;
    child.foo();
    child.bar();
    child.fun();
 
    SomeChild someChild;
    someChild.foo();
    someChild.fun();
}
0
 Аватар для Martein
704 / 109 / 21
Регистрация: 22.06.2014
Сообщений: 241
11.08.2015, 18:45
Согласен, какая задача, такое и решение. Просто ещё один из вариантов и в нём мы можем контролировать момент преобразования типа.
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
11.08.2015, 18:56
Цитата Сообщение от kquick Посмотреть сообщение
Например от базового класса наследуются классы без ограничений.
это смотря как наследоваться.

например:

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
struct Cat
{
    void Sound();  // умеет мяукать
    void Move();  // умеет двигаться
};
 
struct Dog: protected Cat  //<--- защищенное наследование сообщает компилятору
     // что собака наследует функционал кошки (умения), но при этом кошкой собака не является
{
    void Sound();  // умеет гафкать
 
    // функция член движения Move одинаковая для обоих классов
    // и поэтому собака тупо унаследовала этот функционал
 
    using::Move;
   
};
 
 
void foo(Cat& c)   // <--- принимает кошек
{  ... }
 
 
int main()
{
    Dog d;
    foo(d); // ошибка: приведение возможно, но не доступно
}
Цитата Сообщение от kquick Посмотреть сообщение
И есть некоторый "наследник", который не должен показывать методы базового класса.
суть в том, что вы можете как угодно открывать или скрывать методы базовых классов.
разрешать или запрещать приведения типов, и тп.
агрегация для этого не нужна, и занимает больше буковок.



агрегация нужна тогда, когда нужен "агрегат".

что такое "агрегат"?

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

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

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

третий класс ещё за что то своё отвечает.

эти классы изначально не связанны.

и нужен дополнительный класс "персонаж", который объединит внутри себя эти компоненты.
и обеспечит их совместное взаимодействие.

вот для этого используется агрегация:
слаженное взаимодействие различных компонентов.

а не для того, что бы скрывать/раскрывать функционал отдельно взятых компонентов.
1
11.08.2015, 18:58

Не по теме:

Цитата Сообщение от hoggy Посмотреть сообщение
когда я его писал, я ещё не видел #6
Блин, точно. Одно и то же ведь. "Смотрю в книгу, вижу фигу", ппц... Спать пора, мозг явно устал, очевидных вещей не видит.

0
 Аватар для gromo
383 / 281 / 31
Регистрация: 04.09.2009
Сообщений: 1,225
11.08.2015, 20:03
Цитата Сообщение от hoggy Посмотреть сообщение
// ошибка: приведение возможно, но не доступно
Кстати, в Qt такое встречается в так называемых приватных сигналах: подписаться на него можно, однако испустить из клиентского кода уже никак нельзя, ибо ошибка доступа.
2
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
11.08.2015, 23:32
Цитата Сообщение от kquick Посмотреть сообщение
Применение: Например базовый класс содержит большое число методов, а в некотором наследнгике нужно только пару штук и мы не хотим, чтобы весь талмут методов вылазил в IDE как подсказка.
Это паттерн Адаптер. Моделирует отношение "реализуется посредством". Можно сделать либо через закрытое наследование, либо сделав объект используемого класса членом адаптера, либо поместить в адаптер указатель на объект используемого класса.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.08.2015, 23:32
Помогаю со студенческими работами здесь

Вызов наследуемых методов из базового класса
Всем доброго времени суток, перейду сразу к сути. Код: class Base { protected: public: virtual void...

Вызов переопределенного метода из методов базового класса
Здравствуйте, у меня есть два класса, базовый и производный. В производном классе я переопределяю два метода method1 и method2. В базовом...

Запрещение перегрузки public методов базового класса
Можно ли запретить наследникам перегружать public методы базового класса? Если да то как? class base { public: void...

ООП. Наследование переменных и методов от Базового класса к Дочернему и наоборот
class Money : { public: int Selection() { //Здесь играет роль SumToGrn(double &amp;Sum) которую текущий базовый класс не видит. ...

Унаследоваться от базового класса и переопределить часть его данных
Есть базовый класс с некоторыми (protected) данными, в том числе объявленными const, и (public) виртуальными функциями. Требуется...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Камера 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, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru