Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
gameman
0 / 0 / 0
Регистрация: 23.02.2012
Сообщений: 6
#1

Группировка функций разных классов - C++

23.02.2012, 18:35. Просмотров 865. Ответов 12
Метки нет (Все метки)

Всем привет!

Возник спорный вопрос. Задача:
Есть много классов, но у каждого из них может быть (! а может и нет) по методу, например, следующий набор: fnc1, fnc2, fnc3. Программа должна вызвать эти функции независимо от класса и его свойств. Точнее в программе создаются по 1 (скорее по нескольку) экземпляров классов, а программа должна вызвать у каждого из них один и тот же метод.

Я нашел только 2 решения: использовать указатели на статические функции (пихать их в массив и не задумываться) и использовать чистые виртуальные функции (Есть некий класс-"шаблон" с чистыми вирт. функциями, который наследуется всеми остальными. А дальше просто пихаю указатели на экземпяры классов в массив, и вызываю необходимые методы в виде
C++
1
((Parent *)pointer)->fnc();
), но как тогда быть если какой-то функции нет в классе?

И еще вопрос: что быстрее? Мне важна даже самая капелька времени.

Зачем это нужно? Это нужно когда основная программа не должна знать и заботиться о других классах. Что, в свою очередь, необходимо для быстрого расширения спектра возможностей.

Спасибо за внимание!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.02.2012, 18:35
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Группировка функций разных классов (C++):

Динамическая подстановка функций из разных классов - C++
Всем привет! Собственно есть вот такое... struct MyStruct { int index; MyStruct *next, *prev; }; class MyClass { public:

Разработать иерархию классов, демонстрирующее работу с коллекцией объектов разных классов - C++
Задание: Разработать в соответствии с индивидуальным заданием иерархию классов и приложение, демонстрирующее работу с коллекцией объектов...

Множественное наследование, Перегрузка функций, Перегрузка операторов, Использование дружественных функций и классов, Использование шаблонов классов - C++
Здравствуйте!!! Я бы хотел попросить помоч решить...ну или скинуть примеры таких задач, если вдруг у вас они завалялись на компе или...

Передача структур разных классов - C++
Доброго времени суток. Сложилась такая проблема: В метод одного класса нужно передать структуру другого класса. CmatrixDial.h ...

Умножение матриц разных классов - C++
Допустим есть 2 класса, описывающих матрицы А и Б, как произвести с ними арифметические операции(сложение, умножение)?

Взаимодействие объектов разных классов - C++
Я или туплю или чего-то не понимаю\не до понимаю. Вопрос в самом коде. class Player { int health; int damage; public: ...

12
Gepar
1178 / 534 / 20
Регистрация: 01.07.2009
Сообщений: 3,517
23.02.2012, 18:39 #2
Цитата Сообщение от gameman Посмотреть сообщение
но как тогда быть если какой-то функции нет в классе?
Если вы о использовании полиморфизма то чтобы такого не было делают родительский полностью виртуальный класс с какой-то функцией, а все классы наследники уже потом определяют её. Пример нужен или и так понятно?

Добавлено через 1 минуту
Цитата Сообщение от gameman Посмотреть сообщение
И еще вопрос: что быстрее?
Ну так замерьте же время, проделайте так 100 (или 1000) операций и так и сравните время выполнения Я лишь знаю что виртуальные таблицы вещь не очень быстрая по сравнению с обычными вызовами, но в цифрах ничего сказать не могу.
0
gameman
0 / 0 / 0
Регистрация: 23.02.2012
Сообщений: 6
23.02.2012, 18:44  [ТС] #3
Цитата Сообщение от Gepar Посмотреть сообщение
Если вы о использовании полиморфизма то чтобы такого не было делают родительский полностью виртуальный класс с какой-то функцией, а все классы наследники уже потом определяют её. Пример нужен или и так понятно?
Вы имеете в виду делать не чистые, а простые виртуальные функции, которые ничего не делают? Нет, пример не нужен, спасибо.

Добавлено через 3 минуты
Цитата Сообщение от Gepar Посмотреть сообщение
Ну так замерьте же время, проделайте так 100 (или 1000) операций и так и сравните время выполнения Я лишь знаю что виртуальные таблицы вещь не очень быстрая по сравнению с обычными вызовами, но в цифрах ничего сказать не могу.
Так в том то и дело! Я делал замер на 10 млн. вызовов, и время практически одинаковое. Что с оптимизациями, что без. Из-за погрешностей, там то одни функции опережали, то другие, но разница была все равно незначительной. Да нет проблем использовать статику, но ведь код становится куда красивее и приятнее с использованием виртуалок. Но как я и сказал, мне дорога каждая капля времени. Да и мб есть еще какие способы?
0
silent_1991
Эксперт С++
4989 / 3046 / 149
Регистрация: 11.11.2009
Сообщений: 7,028
Завершенные тесты: 1
23.02.2012, 18:55 #4
gameman, если встают такие проблемы - значит архитектура изначально была неверной. Чтобы всё было красиво с точки зрения проектирования, надо вводить дополнительные промежуточные классы в иерархию, которые будут добавлять к предкам новые методы, и наследовать нужные конкретные классы от этих промежуточных. Чтобы всё красиво вызывалось, когда надо, следует использовать dynamic_cast и смотреть, подклассом какой ветви в иерархии является тип конкретного объекта, и в зависимости от этого вызывать нужные методы. Но вот как это отразится на производительности...
0
gameman
0 / 0 / 0
Регистрация: 23.02.2012
Сообщений: 6
23.02.2012, 19:18  [ТС] #5
silent_1991, Могу привести пример.
Есть игра. Есть различные предметы, например: стул, чашка, дверь.
Есть действия пользователя и функции, обрабатывающие их, например: Левый клик мыши по предмету - LClick()
Есть методы прорисовки в буфер - Draw()
Так вот, я же не буду делать вот так:

C++
1
2
3
4
5
for(i = 0; i < кол-во объектов; i++){
    if(obj[i].type == "стул")
        ((Стул *)obj[i].pointer)->Draw();
    // ... и так далее для каждого типа
}
Дверь имеет обработчика левого клика, а вот стул и чашка - нет.
И вот по добавлению каждого нового предмета в игру я должен буду менять внутренности игры? Мне это кажется нелогичным.
0
silent_1991
Эксперт С++
4989 / 3046 / 149
Регистрация: 11.11.2009
Сообщений: 7,028
Завершенные тесты: 1
23.02.2012, 19:22 #6
gameman, нет, не будете. Потому что, я полагаю, любой игровой объект умеет рисоваться. Поэтому метод draw стоит вынести в самый корневой класс, что даст гарантию, что этот метод есть в любом наследнике. Но стул не умеет испускать свет, поэтому любой объект, который мы хотим "включить" на освещение, должен быть проверен на принадлежность соответствующему уровню иерархии.
0
Gepar
1178 / 534 / 20
Регистрация: 01.07.2009
Сообщений: 3,517
23.02.2012, 19:23 #7
gameman, так вы ещё и поле тип добавили в каждый класс, мда ...
Почитайте что-то по с++ по полиморфизму, Страуструпа например.
0
gameman
0 / 0 / 0
Регистрация: 23.02.2012
Сообщений: 6
23.02.2012, 19:28  [ТС] #8
Цитата Сообщение от silent_1991 Посмотреть сообщение
вынести в самый корневой класс
Так вот это и есть один из вариантов решения - наследование. А дабы избавиться от if'ов, возникла идея использовать виртуальные функции.

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

Главной целью стоит избежать этих самых if'ов! Да выгодно: 1) Скорость не зависит от количества объектов. 2) При добавлении новых предметов нет необходимости лезть в дебри движка.
0
silent_1991
Эксперт С++
4989 / 3046 / 149
Регистрация: 11.11.2009
Сообщений: 7,028
Завершенные тесты: 1
23.02.2012, 19:30 #9
gameman, ифов не избежать, потому что какие-то действия нужно проделать только для объектов одних типов, какие-то - для других.
0
gameman
0 / 0 / 0
Регистрация: 23.02.2012
Сообщений: 6
23.02.2012, 19:44  [ТС] #10
Цитата Сообщение от Gepar Посмотреть сообщение
gameman, так вы ещё и поле тип добавили в каждый класс, мда ...
Почитайте что-то по с++ по полиморфизму, Страуструпа например.
Ну разве мне логично создавать по экземпляру класса для каждой вещи если их может быть более 5 млн (деревья, например)?
Я неправильно там написал кусок кода (он приведен для примера).

Вот что я имел в виду:
C++
1
2
3
4
for(int i = 0; i < count; i++){
if(obj[i].type = "door")      // Вот этих ифов я хочу избежать
Door_handler->Draw(obj[i].param);
}
Вот что у меня есть сейчас:

Объекты: Types - массив, хранящий параметры типов, их функции и указатель на класс-обработчик
C++
1
2
3
for(int i = 0; i < count; i++){
    Types[ obj[i].type ].Draw( Types[ obj[i].type ].HandlerPointer );   /* Статик-функция класса (указатель на нее), передаю ей указатель на класс, т.к. статик функи ничего не знают об экземплярах класса */
}
Добавлено через 2 минуты
Цитата Сообщение от silent_1991 Посмотреть сообщение
gameman, ифов не избежать, потому что какие-то действия нужно проделать только для объектов одних типов, какие-то - для других.
Я не принимаю во внимание обработку действий, типа если нажал, то то-то. Я рассматриваю конкретную вещь, например, активация предмета. В ней я пытаюсь избежать ифов, и это удалось, вопрос только какую технологию лучше использовать (у меня на уме только 2).
0
silent_1991
Эксперт С++
4989 / 3046 / 149
Регистрация: 11.11.2009
Сообщений: 7,028
Завершенные тесты: 1
23.02.2012, 19:53 #11
Вот пример:
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <iostream>
#include <string>
 
// Изначальня иерархия движка -------------------------------------------------
 
class Object
{
public:
    virtual void draw() const = 0;
};
 
class Creature : public Object
{
public:
    virtual void walk() const = 0;
};
 
class Light : public Object
{
public:
    virtual void shine() const = 0;
};
 
//-----------------------------------------------------------------------------
 
// А теперь конкретезируем движок ---------------------------------------------
 
class Human : public Creature
{
public:
    Human(const std::string name):
    m_name(name)
    {
    }
    
public:
    virtual void draw() const
    {
        std::cout << "I am a human. My name is " << m_name << std::endl;
    }
    
    virtual void walk() const
    {
        std::cout << "I can walk and I walk" << std::endl;
    }
    
private:
    std::string m_name;
};
 
class Lamp : public Light
{
public:
    Lamp(int illumination):
    m_illumination(illumination)
    {
    }
    
public:
    virtual void draw() const
    {
        std::cout << "Lamp..." << std::endl;
    }
    
    virtual void shine() const
    {
        std::cout << "Illumination + " << m_illumination << std::endl;
    }
    
private:
    int m_illumination;
};
 
int main()
{
    const size_t size = 5;
    
    Object *objects[size] =
    {
        new Human("John"),
        new Lamp(10),
        new Lamp(20),
        new Human("Jack"),
        new Lamp(4)
    };
    
    Human *human_ptr;
    Lamp *lamp_ptr;
    
    for (size_t i = 0; i < size; ++i)
    {
        objects[i]->draw();
        
        if ((human_ptr = dynamic_cast<Human *>(objects[i])) != 0)
            human_ptr->walk();
        else if ((lamp_ptr = dynamic_cast<Lamp *>(objects[i])) != 0)
            lamp_ptr->shine();
    }
    
    for (size_t i = 0; i < size; ++i)
        delete objects[i];
    
    return 0;
}
Здесь в цикле безусловно вызывается метод draw, поскольку он заведомо есть у всех классов. Но при необходимости происходит конкретизация при помощи условных операторов и динамического приведения типа.
0
gameman
0 / 0 / 0
Регистрация: 23.02.2012
Сообщений: 6
23.02.2012, 20:55  [ТС] #12
Цитата Сообщение от silent_1991 Посмотреть сообщение
Вот пример:

Здесь в цикле безусловно вызывается метод draw, поскольку он заведомо есть у всех классов. Но при необходимости происходит конкретизация при помощи условных операторов и динамического приведения типа.
Спасибо за исходник, еще пара мыслей пришла в голову. Но ведь я же изначально сказал что есть похожий (такой же по принципу) способ =)
Хотел полюбопытствовать по поводу ваших мнений и других возможных вариантов. Ну ладно, всем большое спасибо за помощь! Если есть что еще интересное, то выкладывайте!
0
villu
203 / 204 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
23.02.2012, 23:47 #13
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
#include <iostream>
#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
 
using namespace std;
 
class T1 {
public:
    void draw() {
        std::cout << "This is t1!\n";
    }
};
 
class T2 {
public:
    void another_draw() {
        std::cout << "This is t2!\n";
    }
};
 
int main()
{
 
    T1 t1;
    T2 t2;
 
    typedef boost::function<void (void)> function_type;
    std::vector<function_type> funcs;
 
    funcs.push_back(boost::bind(&T1::draw, &t1));
    funcs.push_back(boost::bind(&T2::another_draw, &t2));
 
    funcs[0]();
    funcs[1]();
 
    return 0;
}
This is t1!
This is t2!
Добавлено через 2 часа 34 минуты
кстати, почему-то сразу не подумал, но тебе, скорее всего, нужно что-то типа сигналов.
немного переделанный исходник.
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
#include <iostream>
#include <vector>
#include <boost/signal.hpp>
#include <boost/bind.hpp>
 
 
class T1 {
public:
    void draw() {
        std::cout << "This is t1!\n";
    }
};
 
class T2 {
public:
    void another_draw(bool fast) const {
        std::cout << "This is t2! " << (fast ? "fast" : "slooow") <<  "\n";
    }
};
 
void free_draw_func () {
    std::cout << "This is a free func \n";
}
 
int main()
{
 
    T1 t1;
    T2 t2;
 
    boost::signal<void (void)> funcs;
 
    funcs.connect(boost::bind(&T1::draw, &t1));
    funcs.connect(boost::bind(&T2::another_draw, &t2, true));
    funcs.connect(boost::bind(&T2::another_draw, &t2, false));
    funcs.connect(boost::bind(free_draw_func));
    funcs();
 
    return 0;
}
This is t1!
This is t2! fast
This is t2! slooow
This is a free func
0
23.02.2012, 23:47
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.02.2012, 23:47
Привет! Вот еще темы с ответами:

Сложить объекты двух разных классов - C++
Здравствуйте, при изучении программирования всплыл такой вопрос. Без объявления базового класса, возможно ли сложить 2 их объекта? И как...

Объявлние классов в разных заголовочных файлах - C++
Приветствую всех участников форума. Есть 2 класса А и В. Каждый из содержит указатель на другой класс. Как сделать объявление классов в...

Массив объектов разных производных классов - C++
Задача такая: базовый класс - фигура, производные классы - круг, треугольник и т.п. Пользователь выбирает, какие фигуры будут на экране и...

Хранение в контейнере обьектов разных классов - C++
Здраствуйте. Есть небольшая иерархия классов, в вершине которой стоит абстрактный класс vehicle, а от него наследуеться пару классов....


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.