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

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

14.09.2020, 20:52. Показов 6174. Ответов 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
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
16.09.2020, 12:08
вобщем над зависимостями - ещё подумать...
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 12:09
Цитата Сообщение от JeyCi Посмотреть сообщение
вобщем над зависимостями - ещё подумать...
Это называется иерархия, а не зависимости
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
16.09.2020, 12:10
но конкретно по примеру - это просто его рацион - переобозвать класс Cachalot на CashalotMenu
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
16.09.2020, 12:11
Над ней всегда надо думать. И над зависимостями тоже. Ошибки проектирования - самые дорогие ошибки.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
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
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
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
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
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
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
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
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
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
Ответ Создать тему
Новые блоги и статьи
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20%
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru