Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/40: Рейтинг темы: голосов - 40, средняя оценка - 4.63
 Аватар для murtukov
10 / 10 / 5
Регистрация: 30.01.2013
Сообщений: 99

Наследование и расширение классов

04.05.2016, 01:14. Показов 8301. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!

Не могу решить кое-какую проблему. Допустим я подключил к своему проекту библиотеку, состоящую из четырех классов: абстрактный класс Shape и его производные Circle, Rectangle и Triangle.
Мне необходимо расширить все три дочерних класса, дополнив их ОДИНАКОВЫМ функционалом. То есть, например, я хочу в каждый клаcс добавить функцию getSize(). Как можно этого добиться?

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

Был еще один вариант: создать собственные 4 класса MyShape, MyCircle, MyRectangle и MyTriangle. В классе MyShape прописать все необходимые мне новые функции, а остальные три будут наследоваться от него и + от своих "собратьев":

C++
1
2
3
class MyCircle : public MyShape, public Circle {}
class MyRectangle : public MyShape, public Rectangle {}
class MyTriangle : public MyShape, public Triangle {}
Минус такого решения в том, что класс MyShape не имеет доступа к Shape, Circle, Rectangle и Triangle, что собственно и привело меня на этот форум.

Буду рад вашим мудрым советам.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.05.2016, 01:14
Ответы с готовыми решениями:

Автоматическая генерация классов С ++ с UML диаграмм классов. Наследование в с++. Абстрактные классы. WhiteStarUML
Создать классовую модель(желательно в WhiteStarUML), которая включает в себя абстрактный класс CGraphicsObject, его наследник - базовый...

Заменить наследование классов на наследование интерфейсов
#include <iostream> #include <assert.h> using namespace std; int people_on_base = 100; int vehicles_on_base = 100; double...

Наследование классов. Копирование производных классов
Здравствуйте всем, у меня такой вопрос: написал код #include "stdafx.h" class A //Создаем класс А { int mA; ...

16
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.05.2016, 01:37
Цитата Сообщение от murtukov Посмотреть сообщение
дополнив их ОДИНАКОВЫМ функционалом.
одинаковый функционал выносится в базовый класс.

базовым классом у вас является Shape
0
 Аватар для murtukov
10 / 10 / 5
Регистрация: 30.01.2013
Сообщений: 99
04.05.2016, 01:56  [ТС]
Shape - класс из сторонней библиотеки, менять который нельзя. Все четыре класса, Shape, Circle, Rectangle, Triangle - это классы сторонней библиотеки, так что вносить в них изменения невозможно (по крайней мере в моем случае).
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
04.05.2016, 03:23
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

Цитата Сообщение от murtukov Посмотреть сообщение
Shape - класс из сторонней библиотеки, менять который нельзя. Все четыре класса, Shape, Circle, Rectangle, Triangle - это классы сторонней библиотеки, так что вносить в них изменения невозможно (по крайней мере в моем случае).
на языке с++ существует техника, которая называется "примесь" (mixin)
она специально предназначена для подобных случаев, как у вас.
и позволяет внедрять в иерархию наследования
дополнительный промежуточный базовый класс
между конечным наследником, и библиотечным классом.

Цитата Сообщение от murtukov Посмотреть сообщение
Минус такого решения в том, что класс MyShape не имеет доступа к Shape, Circle, Rectangle и Triangle, что собственно и привело меня на этот форум.
при этом миксин имеет полный доступ к библиотечной базе.
а конечный наследник наследует,
как функционал библиотечной базы,
так и дополнительный функционал миксина

пример:

http://rextester.com/JQNJJI97253
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
#include <iostream>
 
// ======================================
 
    /* библиотечный код */
 
struct Shape 
{
    virtual const char* name()const = 0;
    virtual ~Shape() {}
};
struct Circle    : Shape { virtual const char* name()const override { return "Circle"   ; } };
struct Rectangle : Shape { virtual const char* name()const override { return "Rectangle"; } };
struct Triangle  : Shape { virtual const char* name()const override { return "Triangle" ; } };
 
// ======================================
// ======================================
 
    /* расширение клиента */
 
template<class T> struct MyShape: public T
{
    // --- T должно быть Shape, или его наследником
    static_assert(
        std::is_base_of<Shape, T>::value,
        "\n\n   ERROR: MyShape can be parameterized only heir Shape\n\n"
    );
    
    // --- подмешиваем дополнительный функционал 
    // --- в библиотечную иерархию классов
    double getSize()const 
    { 
        // --- при этом мы имеем доступ к функциональности 
        // --- библиотечных базовых классов
        
        // в данном примере будет задействован 
        // унаследованный от библиотечных классов
        // метод name()
        std::cout << this->name() << " has size "<< 0.0 <<std::endl;
        return 0.0; 
    }
};
 
// ======================================
// ======================================
 
    /* клиентские классы наследуются не от библиотечных классов    */
    /* а от клиентского расширения                                 */
    /* которое параметризуется типом библиотечного класса          */
    /* функциональность которого необходима клиентскому расширению */
 
class MyCircle    : public MyShape<Circle>    {};
class MyRectangle : public MyShape<Rectangle> {};
class MyTriangle  : public MyShape<Triangle>  {};
 
// ======================================
// ======================================
 
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    MyCircle().getSize();
    MyRectangle().getSize();
    MyTriangle().getSize();
    
}
6
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
04.05.2016, 11:37
murtukov, непонятно, ваша функция getSize() должна различать разновидности фигур?
Если да, то пример hoggy не подходит, и нужно применять множественное наследование.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
04.05.2016, 11:45
Цитата Сообщение от hoggy Посмотреть сообщение
которая называется "примесь" (mixin)
а я почему-то адаптер его называл
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
04.05.2016, 12:12
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
а я почему-то адаптер его называл
Не, адаптер как раз и подразумевает множественное наследование.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
04.05.2016, 12:44
Mr.X, напротив.

C++
1
2
3
4
5
6
// myLib.lib
class LibarySprite;
 
// my.exe
class Sprite  : public LibarySprite; // adapter
class ClickableSprite : public Sprite; // used adapter class
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
04.05.2016, 12:52
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Mr.X, напротив.
А вы из какой книжки сведения черпаете? Я из банды четырех.
0
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
04.05.2016, 14:03
Mr.X, я лишь из личного опыта и граблей использования Open Source интерфейсов классов и последующем изменении строк своего кода если там плюнут на обратную совместимость. Именно по описанию паттерна Адаптер, я предпологаю, что это одна из его разновидностей - использовать в проекте свой "прокси-адаптер" библиотечного класса, и наследоватся/расширять интерфейс от своего класса.
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
04.05.2016, 14:39
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Mr.X, я лишь из личного опыта и граблей использования Open Source интерфейсов классов и последующем изменении строк своего кода если там плюнут на обратную совместимость. Именно по описанию паттерна Адаптер, я предпологаю, что это одна из его разновидностей - использовать в проекте свой "прокси-адаптер" библиотечного класса, и наследоватся/расширять интерфейс от своего класса.
Ну, меня всегда забавляет, когда люди пишут свои фантазии и предположения в такой форме, как будто это достоверная информация из книжки.
В книжке банды четырех описывается две разновидности паттерна Адаптер:
● Одна, которая должна различать подклассы библиотечного класса, наследует базовый библиотечный класс, а также интерфейс того класса, функции которого нужно добавить.
● Если же подклассы библиотечного класса новым функциям различать не нужно, то в адаптер добавляется ссылка на объект класса с добавляемыми функциями (результат работы будет такой же, как и в примере hoggy ).
1
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.05.2016, 18:32
Цитата Сообщение от Mr.X Посмотреть сообщение
В книжке банды четырех описывается две разновидности паттерна Адаптер:
согласно банде, Александресску, и вообще, общепринятому мнению,
адаптер - паттерн, задача которого
привести чужеродный интерфейс к виду,
который ожидают клиенты.

область применения:
интеграция внешних компонентов в родную систему.

пример:

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

тут он потырил у Коли класс анимации.
но у Коляныча аналогичный метод называется Out

и вот что бы интегрировать изначально чужеродный компонент
в свою систему, Вася применяет паттерн "адаптер":
C++
1
2
3
4
5
6
7
8
9
10
11
struct Animation 
{
    virtual void Out(); //<--- Коляновый мопед
};
 
struct animation: imedia <--- адаптер над Колянычем
{
    virtual show() { mAnim.Out(); }
private:
    animation m_anim;
};
Добавлено через 51 секунду
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
а я почему-то адаптер его называл
задача адаптера - привести изначально несовместимый интерфейс
к нужному виду.

задача примеси - подмешать к уже существующему функционалу,
какой то дополнительный
3
2549 / 1208 / 358
Регистрация: 30.11.2013
Сообщений: 3,826
06.05.2016, 20:52
hoggy, ну а в данном случаи выступить в виде слоя абстракции между двумя отдельно компилируемо-линкуемыми объектами это адаптер или примесь?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
06.05.2016, 22:38
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
ну а в данном случаи выступить в виде слоя абстракции между двумя отдельно компилируемо-линкуемыми объектами это адаптер или примесь?
я про свой личный опыт скажу, хорошо?

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

в каких то обстоятельствах я знаю, какую технику можно применить.

но!

на названиях паттернов лично я пострадал однажды на собеседовании.

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

различия лежат где-то в идеологической плоскости.
(на самом деле в плоскости использования, но она очень тонкая)

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

я просто применяю технику для решения проблемы.

на собеседовании я описал ряд паттернов,
и области их применений.

мне сказали, что я перепутал "фабричный метод" с "шаблонным".
я возразил: ок, пускай я перепутал,
но я перепутал формальное название, а не суть вещей.

а по сути вещей я предоставил рабочее решение.
какая разница как оно формально называется?

после этого мне предложили место помошника тимлида.
1
 Аватар для murtukov
10 / 10 / 5
Регистрация: 30.01.2013
Сообщений: 99
07.05.2016, 15:38  [ТС]
Парни, я конечно извиняюсь, что перебиваю, хотелось бы вернуться к теме.

Цитата Сообщение от Mr.X Посмотреть сообщение
murtukov, непонятно, ваша функция getSize() должна различать разновидности фигур?
Если да, то пример hoggy не подходит, и нужно применять множественное наследование.
Нет, getSize() не должна различать разновидность фигур. Метод должен иметь абсолютно одинаковую реализацию во всех классах. Согласен, не самый удачный пример привел, ведь фигуры измеряются по разному, но это не суть.

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

1) Почему в вашем примере вы используете структуры вместо классов?
2) Функции внутри структур? Так можно? Тогда чем отличается структура от класса?
3) MyCircle().getSize() - непонятен этот момент. Как можно вызывать метод неинстанциированного класса?

Попытался по вашему примеру применить такой же прием в своей задаче - не вышло, ввиду того, что в расширении клиента, кроме дополнительных методов (getSize()), необходимы еще и статические аттрибуты. Кроме того, возникли проблемы с вызовом базового конструктора.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
07.05.2016, 15:50
Цитата Сообщение от murtukov Посмотреть сообщение
1) Почему в вашем примере вы используете структуры вместо классов?
потому что это удобно.

Цитата Сообщение от murtukov Посмотреть сообщение
Функции внутри структур? Так можно? Тогда чем отличается структура от класса?
технически - ничем.

единственное - в класса доступ по умолчанию private,
а у структур - public

Цитата Сообщение от murtukov Посмотреть сообщение
MyCircle().getSize() - непонятен этот момент. Как можно вызывать метод неинстанциированного класса?
инстанцируются шаблоны.
классы не нужно инстанцировать.

здесь вызов конструктора объекта,
что приводит к созданию временного объекта.
а дальше запуск метода этого временного объекта.

Цитата Сообщение от murtukov Посмотреть сообщение
ввиду того, что в расширении клиента, кроме дополнительных методов (getSize()), необходимы еще и статические аттрибуты.
не вижу проблем.

Цитата Сообщение от murtukov Посмотреть сообщение
Кроме того, возникли проблемы с вызовом базового конструктора.
телепаты в отпуске.
1
 Аватар для murtukov
10 / 10 / 5
Регистрация: 30.01.2013
Сообщений: 99
07.05.2016, 17:18  [ТС]
Цитата Сообщение от hoggy Посмотреть сообщение
телепаты в отпуске.
вот, блин. Вечно они где-то шляются, когда так нужны

Ладно, тогда просто покажу, как я пытаюсь решить свою задачу, но вынесу все это в новую тему под заголовком "Миксины / примеси". Думаю многим пригодится.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.05.2016, 17:18
Помогаю со студенческими работами здесь

Наследование классов!
Помогите с задачей!немного закрутила Описать класс студент,который содержит инфу о студенте с помощью наследования,основать класс...

Наследование классов
Здравствуйте. Помогите пожалуйста решить проблему по наследованию классов. Есть базовый класс class parent { ...

Наследование классов в C++
Здравствуйте, вот у меня есть код и компилятор выводит такую ошибку: C:\Users\yaros\Desktop\N.cpp In function 'int main()': ...

Наследование классов
Очень нужна помощь, организую открытое наследование, но постоянно выходят ошибки, не могу понять от чего TForm1 *Form1; class ABK{ ...

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


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru