Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Один класс разного типа


Автор: Enjoy 10.2.2006, 18:46
Здравствуйте!

Как можно сделать так, чтобы неусколько классов могли иметь одно название, одну одинаковую открытую функцию, и абсолютно разные данные внутри?

Пример:
Код

class CEntity
{
private:
  int EntityType;
  int OtherValues;

public:
  int ProcessMessage(int var1, int var2);


Мне нужно, сделать так, чтобы взависимости от того, какой класс будет создан, с тем классом и работать.

Что-нибудь вроде этого:
Код

<vector> CEntity Entities;

CEntity tempentity;
tempentity.tempentity(typeofentity); // Constructor
CEntity.pushback(tempentity);
tempentity.~tempentity(); // Destructor


У всех классов открытая будет только одна функция ProcessMessage(int var1, int var2), которая принимает и выдаёт одинаковые параметры, но делать будет разное, в зависимости от класса.

Я слышал что-то про виртуальные методы. Может быть это относится сюда?

Помогите мне понять, как называется то, что мне нужно...

Автор: Ignat 10.2.2006, 19:24
Шаблоны использовать надо.
http://ad.cctpu.edu.ru/cpp/print/glava23.htm
Еще лучше в книгах почитать, у Страуструпа, кажется, глава 13.

Автор: Fin 10.2.2006, 19:33
Цитата(Enjoy @ 10.2.2006, 17:46 Найти цитируемый пост)

Как можно сделать так, чтобы неусколько классов могли иметь одно название, одну одинаковую открытую функцию, и абсолютно разные данные внутри?

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

Из того, что я понял, можно порекомендовать.
1. Создай базовый класс.
Код

class CBaseEntiry
{
protected:
  int EntityType;
  int OtherValues;
public:
   virtual int ProcessMessage(int var1, int var2);
   CBaseEntiry(void);
   ~CBaseEntiry(void);
};

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

class CEntiry : public CBaseEntiry
{
public:
   virtual int ProcessMessage(int var1, int var2);
   CEntiry(void);
   ~CEntiry(void);
};


Теперь можеш делать указатель на базовый класс и присваивать ему ссылки на дочерние классы.
Код

CBaseEntiry *MyPtr=new CEntiry();
MyPtr->ProcessMessage(1,2);

Здесь будет выполнятся функция описанная в классе CEntiry, хотя ссылка идет на базовый класс.
Добавлено @ 19:36
Согласен с Ignat, все зависит от того, что ты хочеш получить, Если хочеш подменять типы в функции ProcessMessage, тогда шаблоны. Если хочеш подменять действия, тогда описанный мной способ.

Автор: Enjoy 11.2.2006, 10:34
Мне нужно перевести код с C на C++.

Вот обрывки кода:

Код

ENTITY* FireProjectile(
    char*    className,    // Тип снаряда для создания
    ENTITY*    shooter,    // Стрелок/обладатель снаряда
    ENTITY*    parent)    // Родитель scene graph’а
{
    ENTITY*    entProj;    // Объект снаряда
    VECTOR3    pos;    // Позиция стрелка/снаряда
    VECTOR3    dir;    // Вектор направления стрелка
    VECTOR3    velocity;    // Вектор скорости стрелка

    // Создать снаряд, как дочерний объект parent’а - scene graph’а
    entProj = EntCreate(className, parent, 0, 0(;
    if (entProj)
    {
        // Получить позицию, направление, и скорость от стрелка
        EntSendMessage(entShooter, EM_GETPOS, (int)&pos, 0);
        EntSendMessage(entShooter, EM_GETDIR, (int)&dir, 0);
        EntSendMessage(entShooter, EM_GETVELOCITY, (int)&vel, 0);

        // Установить новый снаряд
        EntSendMessage(entProj, EM_SETPOS, (int)&pos, 0);
        EntSendMessage(entProj, EM_SETDIR, (int)&dir, 0);
        EntSendMessage(entProj, EM_SETVELOCITY, (int)&vel, 0);
        EntSendMessage(entProj, EM_SETOWNER, (int)entShooter, 0);
        EntSendMessage(entProj, EM_START, 0, 0);
    }
    
    return(entProj);
}


// Тип функции обработки сообщения
typedef int(ENT_PROC)(
    ENTITY*    ent,    // Указатель на контейнер _этого_ объекта
    EM    message,        //EM_... сообщение объекта
    int    var1,        //Общий параметр 1
    int    var2);        //Общий параметр 2


typedef enum entMessageTag
{
    // Операции с классом
    EM_CLSINIT,        // Инициализировать класс, var1 = char*
// - ссылка на данные
    EM_CLSFREE,        // Освободить класс
    EM_CLSSNAME,    // Копировать имя класса в var1

    // Создание и уничтожение
    EM_CREATE,        // Создать объект
    EM_START,        // "Включить" объект
    EM_SHUTDOWN,    // Правильно уничтожить объект
    EM_DESTROY,        // Немедленно уничтожить объект

    // Стандартные действия
    EM_UPDATE,        // var1 = int – время обновления
    EM_DRAW,        // _обычный_ рендеринг

    // Доступ к данным
    EM_SETPOS,        // var1 = VECTOR3* позиция
    EM_GETPOS,        // копировать позицию - VECTOR3 в var1

    ...
} EM;


 // Класс ракеты
typedef struct missileTag structure
{
    char    name[MAX_NAME];
    VECTOR3    velocity;        // Вектор скорости
    VECTOR3    position;        // Позиция в мировом пространстве
    VECTOR3    forceAccum;        // Ускорение силы
    MATRIX4    matModel;        // Матрица ориентации
} MISSILE;

// Ресурсы и общеклассовые переменные, загруженные
// вызовом CLSINIT, и освобождённые вызовом CLSFREE
static MODEL    mdlMissile;
static SOUND    launchSound;
static float    thrust = 100000.0f;

// Обработчик сообщений
int MissileProc(
    ENTITY*    entity,    // Это контейнер объекта
    EM    message,    // Сообщение для обработки
    int    var1,        // Общий параметр 1
    int    var2)        // Общий параметр 2
{
    MISSILE* e;    // Указатель на данные объекта    

    // Получить данные класса объекта из контейнера
    e = ((MISSILE*)entity->data);

    // Обрабатывать любые сообщения, относящиеся к объекту ракеты
    switch (message)
    {
        // Операции с классом
        case EM_CLSNAME:
            strcpy((char*)var1, "MISSILE");
            return(TRUE);
        case EM_CLSINIT:
            return( ClsInit((char*)var1) );
        case EM_CLSFREE:
            return( ClsFree() );

        // Создание и уничтожение
        case EM_CREATE:
            return( Create(ent) );
        case EM_SHUTDOWN:

        case EM_DESTROY:
            return( Destroy(e) );
        case EM_START:
            return( Start(e, var1, var2) );

        //Стандартные действия
        case EM_UPDATE:
            return( Update(e, var1) );
        case EM_DRAW:
            return( Draw(e) );

        //Доступ к данным
        case EM_SETPOS:
            V3Copy(&e->position, (VECTOR3*)var1);
            return(TRUE);
        case EM_SETVEL:
            V3Copy(&e->velocity, (VECTOR3*)var1);
            return(TRUE);
        case EM_SETDIR:
            return(SetDirection(e, (VECTOR3*)var1);

        default:
            return(DefEntityProc(message, var1, var2));
    }
    return(TRUE);
}



typedef struct entityClass
{
    char            name[64];    // Уникальное имя класса
    ENT_PROC        clsProc;    // Обработчик сообщений класса
    struct entityClass* next;    // Следующий класс в списке
} ENTCLASS;



void GameInitClasses(
     char*    dataPath)    // Путь, где объекты могут найти
// свои данные
{
    EntCreateClass(PlayerProc, dataPath, 0);
    EntCreateClass(MissileProc, dataPath, 0);
    ...
}


typedef struct entityTag
{
    ENT_PROC*        Proc;        // Функция обработчика сообщений
    void*            data;        // Данные объекта
    int                guid;        // Уникальный идентификатор
//для сетевой синхронизации
    struct entityTag *parent;    // Родитель или NULL
    struct entityTag *prevSibling; // Предыдущий братский объект или NULL
    struct entityTag *nextSibling; // Следующий братский объект или NULL
    struct entityTag *child;    // Первый дочерний объект
} ENTITY;


ENTITY* EntCreateEntity(char    *className,
                        ENTITY    *parent,
                        int    var1,
                        int    var2);


int EntDestroyEntity(ENTITY* ent);

int EntSendMessage (ENTITY *ent,
                   EM    message,
                   int    var1,
                   int    var2);


int EntSendMessageGuid(int    guid,
                   EM    message,
                   int    var1,
                   int    var2);


int EntSendMessagePre(ENTITY *ent,
                   EM    message,
                   int    var1,
                   int    var2);


 void GameProcessInput()
{
    GetInputEvents(&inputEvent);
    MapInputEventsToGameEvents(&inputEvent,
                            &gameEvent);
    EntSendMessage(entPlayer, EM_USERINPUT,
                (int)&gameEvent, 0);
}

void GameUpdateWordl()
{
    EntSendMessagePre(entWorld, EM_UPDATE,
                    elapsedMs, 0);
    EntSendMessagePre(entWorld, EM_POSTUPDATE, 0, 0);
}

void GameDraw()
{
    // Позволить всем объектам отрисовать себя,
    // и затем затемнить
    EntSendMessagePre(entWorld, EM_DRAW, 0, 0);
    EntSendMessagePre(entWorld, EM_DRAWSHADOW, 0, 0);
    EntSendMessagePre(entWorld, EM_DRAWOVERLAY, 0, 0);

    // Если в режиме отладки, то отрисовать
    // дополнительную информацию об объектах
    if (debugMode)
        EntSendMessagePre(entWorld, EM_DRAWDEBUG, 0, 0);

    // Отрисовать визуализацию редактирования для
    // текущего выбранного объекта
    if (editMode)
        EntSendMessage(entBeingEdited, EM_DRAWEDIT, 0, 0);
}


// Обработать сообщение EM_DAMAGE
static DamageHandler(
     ENTITY*    me,        //
     ENTITY*    sender,    //
     int        hitVal)    //
{
    // Владелец отправителя (если снаряд)
    ENTITY* owner = NULL;

    // Уменьшить мои hitpoint'ы, и проверить - не умер ли я
    me->hitPoints 0= hitVal;
    if (me->hitPoints < 0)
    {
        // Я умер! Получить владельца отправителя сообщения
        // (если таковой существует)
        EntSendMessage(sender, EM_GETOWNER,
                    (int)&owner, 0);

        // Если у отправителя сообщения есть владелец,
        // то это снаряд, поэтому дать его владельцу очки.
        // В противном случае дать очки отправителю сообщения
        if (owner)
            EntSendMessage(owner, EM_GIVEPOINTS,
                                    me->points, 0);
        else
            EntSendMessage(sender, EM_GIVEPOINTS,
                                    me->points, 0);

        // Сказать миру, что я умер
        EntSendMessagePre(world, EM_IMDEAD, 0, 0);

        // Уничтожить себя
        EntSendMessage(me, EM_SHUTDOWN, 0, 0);
    }
}




Прошу помочь.

Автор: Enjoy 12.2.2006, 05:32
Неужели это так сложно?

Автор: chipset 12.2.2006, 06:46
Цитата(Enjoy @ 10.2.2006, 08:46 Найти цитируемый пост)
<vector> CEntity Entities;

Это ты что тут делаешь?
Цитата(Enjoy @ 10.2.2006, 08:46 Найти цитируемый пост)
tempentity.~tempentity(); // Destructor

Порнография (С) BreakPointMAN


Цитата(Enjoy @ 10.2.2006, 08:46 Найти цитируемый пост)
Как можно сделать так, чтобы неусколько классов могли иметь одно название, одну одинаковую открытую функцию, и абсолютно разные данные внутри?

Не понял. Поясни.

Код

Foo a;
Foo b;
a.bar = 3;
b.bar = 5; //разные данные?

Добавлено @ 06:46
Цитата(Enjoy @ 11.2.2006, 00:34 Найти цитируемый пост)
Мне нужно перевести код с C на C++.

А что ты собственно, ожидаешь в ответ? smile

Автор: Enjoy 12.2.2006, 08:02
Собственно нужно создать список из этих Entities(причём заранее не известно, какие вообще Entities там будут храниться) , и посылать этому списку сообщения. А этот список будет перенаправлять сообщения нужно Entity, взависимости от содержания сообщения.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)