Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Класс, который содержит, объект для класса других типов 
V
    Опции темы
Rickert
Дата 30.10.2008, 07:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: 0
Всего: 52



Так и не смог реализовать такую вещь: у меня есть класс, в котором должен быть список объектов, с разным кол-вом параметров.
Код
enum clsType
{
  CLS_BASE = -128,
  CLS_DEMO1,
  CLS_DEMO2
}
class baseClass
{
  public:
    baseClass() {type = CLS_BASE;};
    virtual void commonFunction() = 0;

  clsType type;
};

class demoClass : public baseClass
{
  public:
    demoClass() {i = 0; j = 0;type = CLS_DEMO1;}
    void commonFunction() {printf("demoClass");}

  int i, j;
}

class demoClass2 : public baseClass
{
  public:
    demoClass2() {i = 0; j = 0;type = CLS_DEMO2;}

  string tmpString
}

class classContainer
{
  public:
    classContainer() {}

  aList<baseClass> list;//условный класс списка
};

Теперь смысл в следующем: как мне добавлять в список объекты типа demoClass, demoClass2, чтобы потом, внутир classContainer, распозновать их по типу и работать с ними? Придумал только вместо списка делать указатель типа void.



--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Lazin
Дата 30.10.2008, 09:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Код

baseClass* p = ...;
demoClass2* pp = dynamic_cast<demoClass2>(p);
if (pp)
{
    объект, на который указывает р имеет тип demoClass2
}
else
{
    объект, на который указывает р, имеет какой-то другой тип
}

в принципе, если ты точно знаешь тип объекта, можно просто привести тип и все

PM MAIL Skype GTalk   Вверх
mes
Дата 30.10.2008, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



посмотрите патерн visitor, может подойти для вашей задачи 




--------------------
PM MAIL WWW   Вверх
J0ker
Дата 30.10.2008, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 4
Всего: 14



боже мой
да забудьте вы уже эти касты
во-первых, как правильно заметил mes, есть паттерн visitor для сложных вещей.
для простых вполне достаточно полиморфизма:
Код

class B
{
public:
    virtual ~B() {}
    virtual void doSomething() = 0;
};

class D1: public B
{
public:
    virtual void doSomething() { ... }
};

class D2: public B
{
public:
    virtual void doSomething() { ... };
};

typedef std::list<B *> listB_t;
..........
listB_t listB;
........
for(listB_t::iterator i = listB.begin(); i != listB.end(); ++i)
    i->doSomething();



--------------------
user posted image
PM MAIL   Вверх
Lycifer
Дата 7.11.2008, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 144
Регистрация: 4.11.2007

Репутация: нет
Всего: нет



Базовый класс имеет такое:

enum typeClass{typeBaseClass,typeClassChildren1,typeClassChildren2}

class baseClass
{
protected:
     baseClass(){}//можно все перегрузить дабы не кто не создал объект этого класса кроме наследников

     public:
    virtual typeClass  getType(){return typeBaseClass;}
};

Реализация наследников
class ClassChildren1 : baseClass
{
    typeClass  getType(){typeClassChildren1;}
};
class ClassChildren2 : baseClass
{
    typeClass  getType(){typeClassChildren2;}
};


Используется:
void SomeFunctionClassChildren1(ClassChildren1 obj)
{
}
void SomeFunctionClassChildren2(ClassChildren2 obj)
{
}

void SomeFunction(baseClass obj)
{
     switch(obj. getType())
   {
     case typeClassChildren1:
                SomeFunctionClassChildren1((ClassChildren1)obj);//здесь можно и явное приведение
     break;
     case typeClassChildren1:
                SomeFunctionClassChildren2((ClassChildren2)obj);//здесь можно и явное приведение
    break;
     default:
     assert(false);
   }
}



}





PM MAIL ICQ   Вверх
mes
Дата 7.11.2008, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lycifer @  7.11.2008,  13:43 Найти цитируемый пост)
void SomeFunction(baseClass obj)
{
     switch(obj. getType())
   {
     case typeClassChildren1:

да уж... smile 



--------------------
PM MAIL WWW   Вверх
mes
Дата 7.11.2008, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



вот пример, если классический полиморфизм не подходит и известны на стадии компиляции все используемые типы иерархии
Код


#include <iostream>
#include <vector>

#define VISITABLE(visitor)  public: virtual void Accept (visitor& v) { v.Visit(*this); }
class Base;
class Derived1;
class Derived2;

class IOperation
{
  public:
      virtual ~IOperation () {}
     void operator() (Base* o);
     virtual void Visit(Base&)      =0;
     virtual void Visit(Derived1&)=0;
     virtual void Visit(Derived2&) =0;
};

class Base
{
     VISITABLE(IOperation)
    public:
        virtual ~Base() {}
        void f1 () {  std::cout <<"Base::f1();" <<std::endl; }
};

class Derived1 : public Base
{
     VISITABLE(IOperation)
    public:
        void f2 (int i) {  std::cout <<"Derived1::f2(" <<i  <<");"<< std::endl;  }

};
class Derived2 : public Base
{
     VISITABLE(IOperation)
    public:
        void f3 (int a, int b) {  std::cout <<"Derived1::f3("<<a <<"," <<b <<");"<<std::endl;  }
};

void IOperation::operator() (Base* o) { o->Accept(*this); }

class TestFunc : public IOperation
{
    public:
        TestFunc (int a, int b, int c) : m_a(a), m_b(b), m_c(c) {}

     virtual void Visit(Base& o)     { o.f1();         }
     virtual void Visit(Derived1& o) { o.f2(m_c);      }
     virtual void Visit(Derived2& o) { o.f3(m_a, m_b); }

     private:
        int m_a, m_b,m_c;
};

int main ()
{
  std::vector <Base*> v;
  v.push_back(new Base);
  v.push_back(new Derived1);
  v.push_back(new Derived2);

   TestFunc  f (4,5,6);

    for_each (v.begin(), v.end(), f);

  system ("pause");
  return 0;
}




Это сообщение отредактировал(а) mes - 8.11.2008, 16:05


--------------------
PM MAIL WWW   Вверх
Lycifer
Дата 7.11.2008, 17:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 144
Регистрация: 4.11.2007

Репутация: нет
Всего: нет



Цитата

вот пример, если классический полиморфизм не подходит и известны на стадии компиляции все используемые типы иерархии 
 - классический полиморфизм???  smile   это что?smile  - классические интерфеёсы мне известно такое выражение


И как же будеш узновать где какой тип ?
А не тоже самое с раздувжемся кодом ?
А производительность?(не стоит забывать что С++ язык статичиский, визитор это пример более динамического обращения, мой пример можно без проблем перевести к стратегиям что еще ускорит скорость, и к рамеру exe не будет увеличен)
 smile 


PM MAIL ICQ   Вверх
Lazin
Дата 7.11.2008, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Цитата(Lycifer @  7.11.2008,  17:13 Найти цитируемый пост)
А не тоже самое с раздувжемся кодом ?

а твой switch не раздувание кода? smile 
PM MAIL Skype GTalk   Вверх
J0ker
Дата 7.11.2008, 19:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 986
Регистрация: 17.9.2008

Репутация: 4
Всего: 14



Цитата(Lycifer @  7.11.2008,  13:43 Найти цитируемый пост)
 switch(obj. getType())

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


--------------------
user posted image
PM MAIL   Вверх
mes
Дата 7.11.2008, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lycifer @  7.11.2008,  17:13 Найти цитируемый пост)
классический полиморфизм???  smile   это что?smile  - 

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

Цитата(Lycifer @  7.11.2008,  17:13 Найти цитируемый пост)
И как же будеш узновать где какой тип ?

Этим и хорош код, что узнавать какой тип будет компилятор, а программисту лишь надо описать реализацию действия, например
ваш участок кода с самостоятельным слежением за типами и типопреобразованиями
Цитата(Lycifer @  7.11.2008,  13:43 Найти цитируемый пост)
void SomeFunction(baseClass obj)
{
     switch(obj. getType())
   {
     case typeClassChildren1:
                SomeFunctionClassChildren1((ClassChildren1)obj);//здесь можно и явное приведение
     break;
     case typeClassChildren1:
                SomeFunctionClassChildren2((ClassChildren2)obj);//здесь можно и явное приведение
    break;
     default:
     assert(false);
}

аналогичен этому, в котором черная работа осталась за кадром:
Код

class SomeFunc : public IOperation
{
    public:
     
     virtual void Visit(Base& o)       { ..  }
     virtual void Visit(Derived1& o) { ..  }
     virtual void Visit(Derived2& o) { ..  }
};


Ну и что удобней ? 

Цитата(Lycifer @  7.11.2008,  17:13 Найти цитируемый пост)
А производительность?

Двойной вызов виртуальной функции - вот и все накладные расходы.
Цитата(Lycifer @  7.11.2008,  17:13 Найти цитируемый пост)
(не стоит забывать что С++ язык статичиский, визитор это пример более динамического обращения, мой пример можно без проблем перевести к стратегиям что еще ускорит скорость, и к рамеру exe не будет увеличен)

Вот вот - не стоит забывать, что Сpp является языком со статической типизацией. Именно на этой возможности и основан паттерн визитор и в своем исполнении не имеет ни капли динамического 
типопреобразования . Таблица переходов будет определена еще на этапе компиляции. 
Интересно с чего взяли про увелечение кода, при использовании визитора ? ) 
Визитор - это статический свитч, определеный как (в данном случае 2хмерная) таблица переходов, заполняемая и контролируемая, компилятором. 






Это сообщение отредактировал(а) mes - 8.11.2008, 16:06


--------------------
PM MAIL WWW   Вверх
UnrealMan
Дата 8.11.2008, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Цитата(Rickert @  30.10.2008,  08:30 Найти цитируемый пост)
Теперь смысл в следующем: как мне добавлять в список объекты типа demoClass, demoClass2, чтобы потом, внутир classContainer, распозновать их по типу и работать с ними? Придумал только вместо списка делать указатель типа void.

Юзай boost::ptr_list
PM MAIL   Вверх
Lycifer
Дата 11.11.2008, 11:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 144
Регистрация: 4.11.2007

Репутация: нет
Всего: нет



Цитата

Теперь смысл в следующем: как мне добавлять в список объекты типа demoClass, demoClass2, чтобы потом, внутир classContainer, распозновать их по типу и работать с ними? Придумал только вместо списка делать указатель типа void.
 - это был вопрос, я думаю автору нужно знать и иметь доступ к получению типа, в любой момент,(typeid не будем обсуждать это довно забытое), к тамуже пример который приводит mes - способен решать немного другую проблему "когда не имеет значения тип объекта" - а вот это иногда не подходит, obj. getType() -  это обращения такого вида
 - покажи что ты умееш
 - Умееш так , тогда делай вот это .....
 - А так ты так не умееш тогда делай по другому .... 
Но в моём примере есть не достаток когда код растет(Добовляются новые классы удалять старые очень сложно особенно если это по коду разброссано, но это уже другой разговор)
PM MAIL ICQ   Вверх
mes
Дата 11.11.2008, 14:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Lycifer @  11.11.2008,  11:33 Найти цитируемый пост)
Но в моём примере есть не достаток когда код растет(Добовляются новые классы удалять старые очень сложно особенно если это по коду разброссано, но это уже другой разговор) 

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


Цитата(Lycifer @  11.11.2008,  11:33 Найти цитируемый пост)
- покажи что ты умееш
 - Умееш так , тогда делай вот это .....
 - А так ты так не умееш тогда делай по другому ...

А чем хуже такое ?
- а ну ка выполни это так, как умеешь. Но чтоб было хорошо!

Основная  прелесть ООП в том, что можно заставить объект самого решать поставленую задачу.
Механизм виртуальных функций, помогает в этом, позволяя осуществить позднее связывание реализации с интерфейсом и при этом соблюсти все проверки типов на стадии компиляции.

Классический полиморфизм используются для решния задач, когда кол-во выполняемых стабильно, в отличии от иерархии классов.
Т.е мы знаем интерфейс но не знаем сколько и каких объектов будет.
Двойная диспатчеризация (паттерн визитор) применяется в обратном случае, когда иерархия известна и стабильна, но интерфейс должен допускать легкое расширение функционала.

Цитата(Lycifer @  11.11.2008,  11:33 Найти цитируемый пост)
я думаю автору нужно знать и иметь доступ к получению типа, в любой момент

вот код показывающий имя типа, аналогично можно  добавить числовый идентификатор, чтоб узнавать его и использовать в любой момент времени   smile 
(основан на классах из предыдущего примера)
Код

class GetTypeNameOperation : public IOperation
{
    public:
     GetTypeName  ()  { m_Res = "NullType"; }
     string Result ()     { return m_Res; }

   public:
     virtual void Visit(Base& o)       { m_Res = "Base";        }
     virtual void Visit(Derived1& o) { m_Res = "Derived1";  }
     virtual void Visit(Derived2& o) { m_Res = "Derived2";  }
   private:
       string m_Res;
      
};

string GetTypeName (Base *b)
{
      GetTypeNameOperation op; 
      op(b); return op.Result;
}

void PrintTypeName (Base *b)
{
     std::cout <<" Type name of object is " <<GetTypeName (Base *b); << endl;
}

int main()
{
  std::vector <Base*> v;
  v.push_back(new Base);
  v.push_back(new Derived1);
  v.push_back(new Derived2);

  for_each (v.begin(), v.end(), &PrintTypeName)
  
  return 0;
}




--------------------
PM MAIL WWW   Вверх
Lycifer
Дата 11.11.2008, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 144
Регистрация: 4.11.2007

Репутация: нет
Всего: нет



Цитата

А чем хуже такое ?
- а ну ка выполни это так, как умеешь. Но чтоб было хорошо!
  -

А если выполнить надо операции не имеющиго прямого связаности с классом? А тогда все просто мы просто зделаем прямую зависимоть нашего VISITOR от старонних действий!! 
1)Локализация логики  -  чего? не она негодится мы же программисты серьёзные мы все зделаем в одном VISITOR'S(набит как самосат но работает......)

2)VISITOR'S он способен выполнить действия которые были у него внутри, то и есть что бы он что-то еще выполнил лезим во все классы, а что? Нам что не хочется перелопатить еще строк так это N стока? Да не , мы же программисты и постоянная отладка и печать текста нам по приколу......

3)

Цитата

string GetTypeName (Base *b)
{
      GetTypeNameOperation op; 
      op(b); return op.Result;
}
void PrintTypeName (Base *b)
{
     std::cout <<" Type name of object is " <<GetTypeName (Base *b); << endl;
}
  вот это ООП ........


4) Динамический полиморфизм стал классическим  smile  - и какая здесь связь?(вообщен это всё классический интерфейсы) классикой полиформизма была перегрузка функций унаследованная от С то и есть что статический полиморфизм был зараждён ранее и его до сех пор используют , а динамический не все используют и он сравнительно новый(виртуальная таблица это последние что было в полиморфизме на сегоднишний день, к стати реализация виртульной таблицы считается классикой если реализовывать по средством С, в принципе это не таблица а указатель vtbl, но  это другой вопрос....)

5) 
Цитата

Двойной вызов виртуальной функции - вот и все накладные расходы.
 - это мало? по крайне мери это намного медленее чем вызов обычной функции без фычесления адресса.



PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1491 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.