Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.80/25: Рейтинг темы: голосов - 25, средняя оценка - 4.80
 Аватар для SkYMaaN
25 / 19 / 9
Регистрация: 05.04.2019
Сообщений: 338

Зачем нужны виртуальные функции если есть перегрузка?

14.09.2020, 20:52. Показов 6529. Ответов 53

Студворк — интернет-сервис помощи студентам
Есть следующий код:
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
#include <iostream>
using std::cout;
using std::endl;
class Gun
{
public:
    virtual void shoot()
    {
        cout << "Выстрел!" << endl;
    }
};
class SubmachineGun : public Gun
{
public:
    void shoot() override
    {
        cout << "Выстрел! Выстрел! Выстрел! Выстрел!" << endl;
    }
};
 
int main()
{
    setlocale(LC_ALL, "");
    Gun obj; obj.shoot();
    SubmachineGun obj1; obj1.shoot();
}
Если убрать наследования и ключевые слова override and virtual - результат функций не меняется, каждая выполняет свою реализацию.
В чём тогда преимущество виртуальных функций перед следующим кодом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Gun
{
public:
    void shoot()
    {
        cout << "Выстрел!" << endl;
    }
};
class SubmachineGun
{
public:
    void shoot()
    {
        cout << "Выстрел! Выстрел! Выстрел! Выстрел!" << endl;
    }
};
Или даже перед таким кодом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Gun
{
public:
    void shoot()
    {
        cout << "Выстрел!" << endl;
    }
};
class SubmachineGun
{
public:
    void shoot(int count)
    {
        for (size_t i = 0; i < count; i++)
        {
            cout << " Выстрел!";
        }
    }
};
Прошу не бить меня палками, просто пытаюсь понять.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
14.09.2020, 20:52
Ответы с готовыми решениями:

Зачем нужны массивы, если есть обычные переменные?
Здравствуйте. У меня есть вопрос. Зачем нужны массивы, если есть обычные переменные? Можно ведь написать не так: int a= {6,5}; а так:...

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

Зачем нужны виртуальные методы?
Тут она не виртуальная Student s; Person &amp;p = s; s.name(); //Student::name() p.name(); //Person::name() А тут наоборот ...

53
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 12:05
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от JeyCi Посмотреть сообщение
ну в экосистеме - как бы да... если его жизнь окончится - бактерии начнут его кушать...
Тоже не угадала. У тебя выходит, что вся возможная еда получается только из кашалотов
0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
16.09.2020, 12:08
вобщем над зависимостями - ещё подумать...
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 12:09
Цитата Сообщение от JeyCi Посмотреть сообщение
вобщем над зависимостями - ещё подумать...
Это называется иерархия, а не зависимости
0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
16.09.2020, 12:10
но конкретно по примеру - это просто его рацион - переобозвать класс Cachalot на CashalotMenu
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 12:11
Над ней всегда надо думать. И над зависимостями тоже. Ошибки проектирования - самые дорогие ошибки.
1
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
16.09.2020, 12:12
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Это называется иерархия, а не зависимости
вот чтобы зависимости разорвать - и используется создание иерархии, насколько понимаю... ?

Добавлено через 29 секунд
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ошибки проектирования - самые дорогие ошибки.
0
16.09.2020, 12:22

Не по теме:

Цитата Сообщение от JeyCi Посмотреть сообщение
Спасибо
всё верно поняли. Надо мне было два разных наследника создать типа:
C++
1
2
3
4
5
6
7
BaseClass_obj *baseClass_obj_ptr ;
ChildClass childClass1_ob1 ;
ChildClass childClass2_ob2 ;
baseClass_obj_ptr = &childClass_ob1 ;
baseClass_obj_ptr ->virtual_method_of_concrete_child();
baseClass_obj_ptr = &childClass_ob2 ;
baseClass_obj_ptr ->virtual_method_of_concrete_child();
что и мыслилось, но писал без компиляции и был невнимателен. Каюсь)

0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
16.09.2020, 12:47
Цитата Сообщение от JeyCi Посмотреть сообщение
вот чтобы зависимости разорвать - и используется создание иерархии, насколько понимаю... ?
наверно, тоже без компиляции написала... т.к. чтобы разорвать зависимости - можно и вообще в отдельные классы выделять, не входящие в иерархию... имхо

Добавлено через 4 минуты
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
обойтись без неё (динамической памяти) крайне сложно, да и не нужно. Нужно просто минимизировать такое выделение памяти. Но это тоже надо уметь.
всё - поняла/вспомнила !! - стэк быстрый, но очень маленький - поэтому переходят на использование кучи...
попробую это "делать с умом":
1. располагать в куче не всё скопом (не всё MenuForCachalot, а только Food1 или Food2, когда что надо), что надо, например, на завтрак и т.д.!
2. И Удалять вовремя
- полагаю "с умом" - именно это имеет ввиду...
- спасибо!
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 12:52
Цитата Сообщение от JeyCi Посмотреть сообщение
вот чтобы зависимости разорвать - и используется создание иерархии, насколько понимаю... ?
Вопрос организации иерархии/взаимодействия классов и объектов, он довольно сложный и сильно зависит от предметной области и постановки задачи. Можно сделать по-разному, но как-то здравый смысл не стоит отключать.

Цитата Сообщение от JeyCi Посмотреть сообщение
всё - поняла/вспомнила !! - стэк быстрый, но очень маленький - поэтому переходят на использование кучи...
Нет, не поэтому. В стеке ты не можешь свободно создавать/удалять объекты. Только добавлять в голову и удалять оттуда же.
В куче же ты можешь это делать в любой последовательности.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
16.09.2020, 13:08
Цитата Сообщение от JeyCi Посмотреть сообщение
всё - поняла/вспомнила !! - стэк быстрый, но очень маленький - поэтому переходят на использование кучи...
попробую это "делать с умом":
Тут 2 вопроса. Первый о управлении временем жизни в большей степени. И о модели владения. Например иногда нельзя позволять создавать объекты ни чем кроме фабрики, а она не может вернуть объект ввиду отсутствия копирующих операций. Тут можно только указатель на объект в куче. Случаев много, но куча это куча. Например кучу флуда нельзя превратить в хорошо упакованный стек.
Что касается ума, то иногда трудно что-то сказать. Например создавая вектор смартпойнтеров память в куче выделяетмя и смартпойнтерами и вектором.
Но важно не это. Жаль видеть гибель темы с хорошим - спасибо ТС названием. Можно бы даже попросить модераторов чуть подправить концовку.
0
16.09.2020, 13:21

Не по теме:

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
но как-то здравый смысл не стоит отключать.
согласна :) - кашалоту и на завтрак и на обед и на ужин - всегда планктон (даже без иерархии можно)... класс растения - можно в др. иерархию - MenuForHamster - и расписать его рацион по классам... потом помещать блюда на, например, завтрак - в кучу... ждать пока съест... и т.д. ...
пример становится всё более реальным :rtfm: нежели абстрактным...
я тоже - за то, чтобы не создавать лишних классов...

0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
17.09.2020, 18:40
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Без виртуальных методов функция WriteLog должна быть шаблонной,
это так что ли?
Кликните здесь для просмотра всего текста
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
#include <iostream>
 
class A
{
    public:
        std::ostream &Format(std::ostream &out) const { return out << "A !!!!";}
};
 
class B : public A
{
    public:
        std::ostream &Format(std::ostream &out) const { return out << "B !!!!";}
};
 
template <typename T> 
void WriteLog(T &obj)
{
    obj.Format(std::cout) << std::endl;
}
 
 
int main()
{
    A a;
    B b;
    WriteLog(a);
    WriteLog(b);
}

но const, наверно, всё-таки убрать?..
всё равно непонятно, зачем ещё и шаблон, если в каждом классе прописывать свой std::ostream& надо?..
(вообще, конечно, этот std::ostream& чаще встречается, как friend, но friend'ы не наследуются)... т.е. шаблон делают, чтобы для каждого не делать своего friend'а?..

Добавлено через 3 минуты
неужели есть какой-то тайный смысл в замене virtual на использование templates?.. бывает ли это резонно? и в каких случаях?.. как-то сильно задумалась над вашей мыслью...
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
17.09.2020, 18:45
Цитата Сообщение от JeyCi Посмотреть сообщение
это так что ли?
Именно

Добавлено через 1 минуту
void WriteLog(T &&obj)

Добавлено через 47 секунд
Цитата Сообщение от JeyCi Посмотреть сообщение
но const, наверно, всё-таки убрать?..
В случае с шаблонами можно убрать. Но лучше оставить

Добавлено через 1 минуту
Цитата Сообщение от JeyCi Посмотреть сообщение
всё равно непонятно, зачем ещё и шаблон, если в каждом классе прописывать свой std::ostream& надо?..
Ну, просто попробуй сделать подобную функцию без шаблонов и виртуальных методов.

Добавлено через 1 минуту
Цитата Сообщение от JeyCi Посмотреть сообщение
неужели есть какой-то тайный смысл в замене virtual на использование templates?.. бывает ли это резонно? и в каких случаях?.. как-то сильно задумалась над вашей мыслью...
Шаблоны - это compile-time. Виртуальные методы - это runtime + накладные расходы
1
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
17.09.2020, 19:24
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Шаблоны - это compile-time. Виртуальные методы - это runtime + накладные расходы
вот это уже радует в шаблонах! спасибо!

Добавлено через 23 минуты
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну, просто попробуй сделать подобную функцию без шаблонов и виртуальных методов.
честно говоря ostream& Format(ostream& out) {/*do_format*/} ещё не напишу...
но с friend'ами как-то так, наверно, - у каждого свой:
Кликните здесь для просмотра всего текста
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
#include <iostream>
 
class A
{
    public:
    friend std::ostream& operator<<(std::ostream& out, A) {
        // output something
        return out << "A !!!!\n";
    } 
};
 
class B : public A
{
    public:
        //std::ostream &Format(std::ostream &out) const { return out << "B !!!!";}
    friend std::ostream& operator<<(std::ostream& out, B) {
        // output something
        return out << "B !!!!\n";
    }
};
 
int main()
{
A a;
   B b;
   std::cout<<a;
   std::cout<<b;
}
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
17.09.2020, 19:25
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну, просто попробуй сделать подобную функцию без шаблонов и виртуальных методов.
oleg-m1973, вопрос в комфорте. Но попробовать всегда можно. Радости от такого мало, - вы правы:
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
#include <iostream>
using namespace std;
 
struct WildCvaziVirtual
{
    using Dynamic_linked_fun=int (*)(int,int);
    WildCvaziVirtual(int a_=0, int b_=0, Dynamic_linked_fun dynamic_linked_fun_=nullptr)
    :a(a_)
    ,b(b_)
    ,dynamic_linked_fun(dynamic_linked_fun_)
    {
 
    }
 
 
    void noVirtualPolymorph()const
    {
 
            if(dynamic_linked_fun)cout<<dynamic_linked_fun(a,b);
            else cout<<"\nsum "<<(a+b);
            cout<<endl;
 
    }
    int a,b;
    const Dynamic_linked_fun &dynamic_linked_fun;
 
};
int mult(int a, int b){cout<<"\nmult " ; return a*b;}
int diff(int a, int b){cout<<"\ndiff " ;return a-b;}
 
void executor(const WildCvaziVirtual &dontcare_what)
{
    cout<<"\nexecutor"<<endl;
    dontcare_what.noVirtualPolymorph();
}
 
 
int main()
{
WildCvaziVirtual sum_obj(2,3), mult_obj(2,3, mult), diff_obj(2,3,diff);
 
executor(sum_obj);
executor(mult_obj);
executor(diff_obj);
 
return 0;
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
17.09.2020, 19:27
Цитата Сообщение от JeyCi Посмотреть сообщение
честно говоря ostream& Format(ostream& out) {/*do_format*/} ещё не напишу...
но с friend'ами как-то так, наверно, - у каждого свой:
Это не то. Не зацикливайся на том, что конкретно делает функция. Речь шла совсем не об этом.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
17.09.2020, 19:33
Или даже так
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
#include <iostream>
using namespace std;
 
struct WildCvaziVirtual
{
    using Dynamic_linked_fun=int (*)(int,int);
    WildCvaziVirtual(int a_=0, int b_=0, Dynamic_linked_fun dynamic_linked_fun_=nullptr)
    :a(a_)
    ,b(b_)
    ,dynamic_linked_fun(dynamic_linked_fun_)
    {
 
    }
 
 
    void noVirtualPolymorph()const
    {
 
            if(dynamic_linked_fun)cout<<dynamic_linked_fun(a,b);
            else cout<<"\nsum "<<(a+b);
            cout<<endl;
 
    }
 
    void noVirtualPolymorph(int a_, int b_)const
    {
 
            if(dynamic_linked_fun)cout<<dynamic_linked_fun(a_,b_);
            else cout<<"\nsum "<<(a_+b_);
            cout<<endl;
 
    }
    int a,b;
    const Dynamic_linked_fun &dynamic_linked_fun;
 
};
int mult(int a, int b){cout<<"\nmult " ; return a*b;}
int diff(int a, int b){cout<<"\ndiff " ;return a-b;}
 
void executor(const WildCvaziVirtual &dontcare_what)
{
    cout<<"\nexecutor"<<endl;
    dontcare_what.noVirtualPolymorph();
}
 
void executor(const WildCvaziVirtual &dontcare_what, int a, int b)
{
    cout<<"\nexecutor_params"<<endl;
    dontcare_what.noVirtualPolymorph(a,b);
}
 
int main()
{
WildCvaziVirtual sum_obj(2,3), mult_obj(2,3, mult), diff_obj(2,3,diff);
 
executor(sum_obj);
executor(mult_obj);
executor(diff_obj);
 
executor(sum_obj,  12,34);
executor(mult_obj, 12,34);
executor(diff_obj, 12,34);
 
return 0;
}
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
17.09.2020, 19:34
Цитата Сообщение от IGPIGP Посмотреть сообщение
oleg-m1973, вопрос в комфорте. Но попробовать всегда можно. Радости от такого мало, - вы правы:
Ну да. Здесь используется указатель на функцию. Это та же самая виртуальная функция, только сбоку
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
17.09.2020, 19:38
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну да. Здесь используется указатель на функцию. Это та же самая виртуальная функция, только сбоку
Это механизм виртуального наследования если его освежевать, кастрировать и обидеть грубым словом.
Наследование + полиморфизм, позволяют строить иерархические по данным и логике, RAII управляемые, легко выражаемые структуры.
Виртуально-феерические.
Но если решается шаблонами, то от виртуальности нужно бежать, обычно.
0
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,554
17.09.2020, 19:58
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Речь шла совсем не об этом.
ну так (под спойлером) слишком просто как-то...
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <sstream> 
 
class A
{
    public:
        std::ostream &Format(std::ostream &out) const { return out << "A !!!!";}
        
};
 
class B : public A
{
    public:
        std::ostream &Format(std::ostream &out) const { return out << "B !!!!";}
};
 
int main()
{
    A a;
    B b;
    a.Format(std::cout)<< std::endl;
    b.Format(std::cout)<< std::endl;
}

вообще, я, конечно, не экстрасенс... но над тем, что будет наследоваться, что нет и как - ещё поработать надо... думаю, вы ведёте к 1-му вопросу ТСа - и ответ будет такой же, как в начале ветки -- просто синтаксис stream'а немного завёрнутый ... завтра посмотрю _ уже, наверно, слепая...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
17.09.2020, 19:58

зачем нужны анонимус-функции? если есть {} и let
Часто вижу подобные куски кода ( function() { ... var a = 5; /// })(); undefined a VM186:1 Uncaught ReferenceError: a...

Зачем нужны модули, если есть пространства имён?
Зачем нужны модули, если есть пространства имён?

Зачем нужны наборы в Evernote, если есть Блокноты?
Зачем нужны наборы в Evernote, если есть Блокноты?

А зачем нужны веб программисты, если есть wordpress?
Открыл я сайт с вакансиями, а там написано &quot;требуется программист php, зарплата 90 тыс в месяц&quot;. Звоню спрашиваю, что вы пишете..они...

Зачем нужны rvalue ссылки, если есть универсальные ссылки
Читаю книгу Скотта Мэйерса... Что-то я совсем запутался с этими rvalue ссылками. Я не пойму, зачем нужны rvalue ссылки, если есть...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru