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


Автор: Anton Vatchenko 2.9.2010, 15:35
Итак, есть некий базовый класс:
Код

class Object
{
public:
    virtual void func() = 0;
};

От него идет целая иерархия классов, типа:
Код

class Car : public Object
{
public:
    virtual void func() { int c = 2; c++; ... }

private:
    int m_r, m_speed;
}

То есть имеем допустим миллион экземпляров "машин" (Car), при этом известно что у всех у них одинаковый функционал, но у каждой свой радиус колес, мощность, выносливость. Нет смысла для каждого экземпляра определять отдельно все эти данные, потому как известно, что среди этого миллиона машин всего 20 характерных типов (Волга, Мерс, БМВ и т.п.) Как данное реализовать, только без создания 20 разных классов, ну кроме указателя на std:map свойств - необходимо делать быстрое чтение этих данных.

Автор: azesmcar 2.9.2010, 15:44
Цитата(Anton Vatchenko @  2.9.2010,  15:35 Найти цитируемый пост)
среди этого миллиона машин всего 20 характерных типов (Волга, Мерс, БМВ и т.п.) Как данное реализовать

а чем отличается класс Волга от класса BMW?

Автор: Anton Vatchenko 2.9.2010, 15:45
Радиусом колес, мощностью. Ну всеми свойствами авто. Но 10 волг между собой отличаются только позицией, ну и текущей скоростью. Радиус, мощность у них одна. Ну и функционал у всех машин один.

Автор: mes 2.9.2010, 15:46
Цитата(Anton Vatchenko @  2.9.2010,  14:35 Найти цитируемый пост)
Как данное реализовать, 

милльен вариантов. Все зависит от решаемой задачи. 


Автор: azesmcar 2.9.2010, 15:47
Цитата(Anton Vatchenko @  2.9.2010,  15:45 Найти цитируемый пост)
Радиусом колес, мощностью. Ну всеми свойствами авто. 

Цитата(Anton Vatchenko @  2.9.2010,  15:45 Найти цитируемый пост)
Ну и функционал у всех машин один.

т.е. как класс ничем не отличается, отличаются лишь значение полей.

Автор: Anton Vatchenko 2.9.2010, 15:47
Очень хотелось бы хоть один, с минимальным количеством подводных камней (кастинг, map свойств и т.п.)

То есть имеем 5 волг, 10 бмв, 3 мерса. Все они имеют разные позиции, но у всех волг один радиус колес, у всех бмв - другой, у всех мерсов - третий. Ну и у всех у них один функционал, просто однажды вызывается типа createWheels(m_typeRadius).

Автор: mes 2.9.2010, 15:48
Цитата(Anton Vatchenko @  2.9.2010,  14:45 Найти цитируемый пост)
Радиусом колес, мощностью. Ну всеми свойствами авто. 

если только этим, то не зачем плодить дополнительные классы. 
достаточно сделать несколько _инициализаторов_ приводящих объект Car в нужное состояние.

Добавлено через 48 секунд
Цитата(Anton Vatchenko @  2.9.2010,  14:47 Найти цитируемый пост)
Очень хотелось бы хоть один, с минимальным количеством подводных камней

задачу в студию smile

Автор: Anton Vatchenko 2.9.2010, 15:50
ну в принципе задача и так описана - есть иерархия классов, экземпляры могут иметь как конкретные свойства (типа позиция, текущий уровень топлива, поворот колес), так и общие (радиус колес, мощность). У всех машин одного типа эти общие свойства и есть общие.

Автор: djamshud 2.9.2010, 15:52
Код

class car_iface{};

class volga{};

class bmw{};

class volga3110:public car_iface,public volga{};


Это самый простой способ, полностью реализованный на одной лишь объектной модели С++. В принципе можно волгу наследовать от интерфейса кар, а волгу-3110 только от волги, но первый вариант мне кажется более гибким.

Автор: Anton Vatchenko 2.9.2010, 15:54
Цитата(Anton Vatchenko @  2.9.2010,  15:35 Найти цитируемый пост)
только без создания 20 разных классов

Если учесть, что марок машин 20, у каждой по 10-20 моделей, то программирование класса для каждой займет месяц.

Автор: mes 2.9.2010, 16:02
Цитата(Anton Vatchenko @  2.9.2010,  14:54 Найти цитируемый пост)
Если учесть, что марок машин 20, у каждой по 10-20 моделей, то программирование класса для каждой займет месяц.

лови и пили :
Код


typedef int wheel_size_t;
typedef int engine_power_t;

class car
{ 
  public:
       struct descriptor_t
       {
             const char *      name;     
             wheel_size_t      wheel_size;
             engine_power_t    engine_power;
//            ...
       };
      car (descriptor_t const& d) : m_descriptor (d) {}
        
  private:
      const descriptor_t& m_descriptor;                   
};

const car::descriptor_t d_car1 = { "car_name_1", 14, 200 };
const car::descriptor_t d_car2 = { "car_name_2", 15, 260 };
const car::descriptor_t d_car3 = { "car_name_3", 15, 250 };


Автор: Anton Vatchenko 2.9.2010, 16:05
А что делать с производными классами? Вот к примеру от Car порождены Car3Wheel, Car4Wheel, у которых могут быть еще свои свойства, частично функционал из Car, а частично из себя?

Автор: mes 2.9.2010, 16:09
Цитата(Anton Vatchenko @  2.9.2010,  15:05 Найти цитируемый пост)
 Car3Wheel, Car4Wheel, 

добавьте в дескриптор поле, о том сколько колес.

Более полно решить задачу не зная задачи, проблематично.. 
Первоначально надо  представить что есть автомибиль и какие задачи он должен решать.
Т.е. автомобиль с точки зрения завода, его производящего, такси-фирмы, и простого пользователя , абсолютно различны и отражать все это в одной модели не имеет смысла 
smile

Автор: Anton Vatchenko 2.9.2010, 16:11
то есть может получиться типа
Код

class Bicycle
{
    const BicycleDescriptor& m_data;
}

class Car : public Bicycle
{
    const CarDescriptor& m_data;
}

которые "увеличат" размер класса, так как в Car будет как бы дважды m_data.

Добавлено через 40 секунд
Задача дана в первом посте, полностью.

Автор: mes 2.9.2010, 16:13
Цитата(Anton Vatchenko @  2.9.2010,  15:11 Найти цитируемый пост)
которые "увеличат" размер класса, так как в Car будет как бы дважды m_data. 

это можно обойти smile 

но Вы уверены, что Car это наследник Bicycle ?!

Добавлено через 3 минуты и 33 секунды
Цитата(Anton Vatchenko @  2.9.2010,  15:11 Найти цитируемый пост)
Задача дана в первом посте, полностью. 

то что описано в первом посте, полностью решается приведенным примером.


Автор: Anton Vatchenko 2.9.2010, 16:22
ну я просто пример привел, может и не Car от Bicycle, а Car и Bicycle от Transport.

как обойти проблему увеличения класса?

Автор: mes 2.9.2010, 16:31
Цитата(Anton Vatchenko @  2.9.2010,  15:22 Найти цитируемый пост)
как обойти проблему увеличения класса? 

желательно ее не создавать smile

если транспорт является общим интерфейсом, то он никаких дескрипторов не хранит и поэтому проблемы наследоваться всем от транспорта нет.
но если все ж надо наследоваться от наследника, то каст спасет мир smile



Автор: Anton Vatchenko 2.9.2010, 16:44
А можно как-то и без каста и без увеличения размера класса? Если класс Transport реализует общий для дочерних классов функционал? При этом как Car и Bicycle наследуется от Transport, так и CarDescriptor и BicycleDescriptor наследуется от TransportDescriptor.

Автор: mes 2.9.2010, 17:38
Цитата(Anton Vatchenko @  2.9.2010,  15:44 Найти цитируемый пост)
 При этом как Car и Bicycle наследуется от Transport, так и CarDescriptor и BicycleDescriptor наследуется от TransportDescriptor. 

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

Автор: Anton Vatchenko 2.9.2010, 17:52
Ну а если у дескриптора транспорта есть общее свойство типа мощность, транспорт в функционале использует это свойство, эти же свойства определены у велосипеда и автомобиля, но еще добавлено множество других...

Автор: mes 2.9.2010, 17:56
я ж написал :
Цитата(mes @  2.9.2010,  16:38 Найти цитируемый пост)
нет, в рамках описанной задачи

остальное допил решает.  smile 

Автор: Anton Vatchenko 3.9.2010, 09:25
ну это и есть основная проблема - как ее решить?

Автор: mes 3.9.2010, 11:15
Цитата(Anton Vatchenko @  3.9.2010,  08:25 Найти цитируемый пост)
ну это и есть основная проблема - как ее решить? 

не вижу проблемы, нельзя ли поподробней ?

Автор: Anton Vatchenko 3.9.2010, 12:40
Вроде уже все много раз описал. При решении, которое мне указали вы, есть иерархия инстансов, и есть иерархия дескрипторов, при этом инстанс указывает на конкретный дескриптор. Как работать с конкретным дескриптором без увеличения размера класса, а также без кастинга?

Автор: mes 3.9.2010, 13:37
Цитата(Anton Vatchenko @  3.9.2010,  11:40 Найти цитируемый пост)
 Как работать с конкретным дескриптором без увеличения размера класса, а также без кастинга?

так не бывает, чтоб все удовольствие в одном флаконе.

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

ну а выглядит примерно так :
Код

struct TransA
{
 
   struct Descriptor { int a; } & m_desc;
   
   void Do () { getDescriptor().a =5; }

   TransA ( Descriptor& d ) : m_desc (d) {}

   Descriptor& getDescriptor () { return m_desc; }
};

struct TransB : TransA {
   
   struct Descriptor : TransA::Descriptor { int b; };

   void Do () { 
                getDescriptor().a =5; 
                getDescriptor().b =6;
   }

   TransB ( Descriptor& d ) : TransA (d) {}

   Descriptor& getDescriptor () {
       return static_cast<Descriptor&> ( TransA::getDescriptor() ); 
   }
};

struct TransC : TransB {
 
   struct Descriptor : TransB::Descriptor { int c; };

   void Do () { 
                getDescriptor().a =5;
                getDescriptor().b =5;
                getDescriptor().c =5;
   }

   TransC ( Descriptor& d ) : TransB (d) {}

   Descriptor& getDescriptor () {
       return static_cast<Descriptor&> (TransB::getDescriptor()); 
   }
};

использовал структуры чтоб не писать приват и паблик, а также специально _забыл_ про константность ссылки.
smile

Автор: Леопольд 3.9.2010, 15:19
mes, выглядит неплохо, но надо помнить что Descriptor не должен быть временным (локальным) объектом. IMHO, лучше "шарить" через shared_ptr.
Код
TransC Make()
{
    TransC::Descriptor descr;
    descr.a = 1;
    descr.b = 2;
    descr.c = 3;
    return TransC(descr);
}

#include <iostream>

int main()
{
   TransC test = Make();
   std::cout<<test.getDescriptor().a<<'\n'
            <<test.getDescriptor().b<<'\n'
            <<test.getDescriptor().c<<std::endl;
   return 0;
}

Автор: mes 3.9.2010, 15:31
Цитата(Леопольд @  3.9.2010,  14:19 Найти цитируемый пост)
 но надо помнить что Descriptor не должен быть временным объектом.


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

но и это решаемо (хотя это уже вроде не по теме)
smile

Автор: Леопольд 3.9.2010, 15:37
Цитата(mes @  3.9.2010,  15:31 Найти цитируемый пост)
хотя это уже вроде не по теме
Это я скорее для Anton Vatchenko отметил... 

Автор: Anton Vatchenko 3.9.2010, 17:22
Спасибо, видимо действительно иначе никак... Значит будем кастить...

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