Как запретить повторное использование конструктора?

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Закрыто
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Сионист писал(а):1. Что странного в том, что синглитон имеет смысл в рамках всего ООП?
Ничего странного в этом нет. Более того, с этим высказывание никто и не спорил. Можешь найти хоть один пост хоть одного человека, который тебе сказал, что синглтон реализуем только на С++?

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

Делаю предположение, что хочется реализовать некую модель из теории множеств. Есть некое множество элементов. Один из элементов выделен в качестве эталонного. Остальные определяются не сами по себе, а как разница между эталонным объектом и собой. Кстати, тут сразу вопрос. Может ли произвольный элемент множества быть определён только как разница от эталонного элемента или же может быть рекурсивная ситуация, когда он определён, как разница от другого не эталонного?

Вкратце по реализации того, что я уже понял. Статическое хранилище всех объектов данного класса внутри самого класса - это зло. Причин много, не хочу сейчас распинаться и всё расписывать. Скажу лишь, что в коммерческом коде в таких случаях обычно используют так называемое "хранилище". Оно не только создаёт объекты, но и отвечает за их владение. То есть вызывающий код не создаёт и не удаляет объекты явно. Он лишь "просит" у хранилища новый объект, получает указатель на него, работает с ним, а потом просто о нём забывает. Наше хранилище, кстати, как раз может быть честным синглтоном, правда при условии, что в объектной модели предполагается только один набор объектов (иначе же отдельное хранилище со своим эталоном на каждый набор).

По поводу создания эталонного объекта. Его создание в любом случае синтаксически отличается от создания остальных, так как ему требуется на один параметр меньше. То есть как минимум в одном месте мы должны будем вызывать для его создания либо специальный конструктор, либо специальный метод "хранилища". А если вызвали один раз, то и второй раз никто не запретит вызвать, даже если это неправильно с точки зрения логики. То есть сделать так, чтобы компиляция упала для второго вызова просто не получится. Проверку придётся делать в рантайме с помощью if. И если эталонный объект уже создан, то бросать исключение из конструктора, либо возвращать NULL из соответствующего метода хранилища.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Romeo писал(а):Ничего странного в этом нет. Более того, с этим высказывание никто и не спорил.
Нем не менее именно Вы зачем то упираетесь в конкретный язык, будто стинглтон - языковая конструкция.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Romeo писал(а):В очередной раз призываю забыть о синглтонах и вернуться к тому, с чего всё началось. Распиши подробнее для каких именно объектов и отношений между ними необходимо создать объектную модель. Давай я попытаюсь объяснить так, как понял, а ты меня исправь, если я понял где-то неправильно.
Для объекта "чёрный полуящик", причём, класс должен знать все свои экземпляры, каждый должен быть элементом одновременно двух контейнеров: извращённого дерева и линейного двусвязного списка, оба этих контейнера должны быть закрыты и "знать" о них должны только конструкторы, деструктор и операторы-члены и некоторые функции-члены данного класса. Знание классом всех экземпляров необходимо для работы функции-члена, выводящей на экран справочник всех экземпляров, оператора-члена, вычисляющего отношение любого экземпляра к любому и функции-члена, ищущей экземпляр по значению закрытого поля и возвращающей константный указатель на найденный экземпляр для присваивания его полю другого класса. Извращение дерева заключается в том, что предок не знает своих потомков, но потомок знает своего непосредственного предка.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Оксалайя
Сообщения: 27
Зарегистрирован: 01 сен 2015, 12:12

И в каком месте Вам здесь понадобилось запретить второй вызов конструктора?
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Romeo писал(а):По поводу создания эталонного объекта. Его создание в любом случае синтаксически отличается от создания остальных, так как ему требуется на один параметр меньше. То есть как минимум в одном месте мы должны будем вызывать для его создания либо специальный конструктор, либо специальный метод "хранилища". А если вызвали один раз, то и второй раз никто не запретит вызвать, даже если это неправильно с точки зрения логики. То есть сделать так, чтобы компиляция упала для второго вызова просто не получится. Проверку придётся делать в рантайме с помощью if. И если эталонный объект уже создан, то бросать исключение из конструктора, либо возвращать NULL из соответствующего метода хранилища.
Компиляция не падает. Но создаётся особый объект, при всяком обращении к которому подставляется объект, созданный первым. Такие специальные объекты исключены из списка. Данная имитация ранее описанной логики достаточна.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Оксалайя писал(а):И в каком месте Вам здесь понадобилось запретить второй вызов конструктора?
Если конструктор без ссылки в первоначальном варианте вызвать дважды. то можно построить две коряги, указывая для их элементов ссылки на экземпляры, созданные при обоих вызовах. Тогда если операнды оператора, вычисляющего отношение двух любых экземпляров, относятся к разным корягам, то оператор падает, либо в него придётся добавлять бросок исключение, что хоть и лишает ошибку фатальности, но обнаруживаться она будет только в рантайме, да и то не всенда и ни когда не будет исправлена. Если же без ссылки создать только один экземпляр, то все ссылки не избежно сойдутся к нему и коряга будет одна.
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Оксалайя
Сообщения: 27
Зарегистрирован: 01 сен 2015, 12:12

Покажите код. Разгрести Ваши формулировки весьма тяжело, не вывихнув мозги.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Картина начинает проясняться. По поводу статических данных я считаю, что список объектов всё же должен быть в отдельном классе-хранилище. А статическое "извращённое" дерево вообще излишняя конструкция, так как для того, чтобы удержать в памяти все связи этого дерева на самом деле достаточно чтобы каждый объект хранил указатель на второй объект из отношения. Этого достаточно, чтобы дерево просто выбросить.

По поводу архитектуры классов, я бы следующим образом всё представил. Это набросок.

Код: Выделить всё

class IObject
{
public:
   // some interface methods of abstract object
   virtual void M_1() = 0;
   /* ... */
   virtual void M_N() = 0;

   virtual ~IObject() {}
};

class CObject : public IObject
{
public:
   // implementation of common object methods
   virtual void M_1()
   {
      // implementation
   }

   /* ... */

   virtual void M_N()
   {
      // implementation
   }

private:
   // some common object data
};

class CRootObject : public CObject
{
public:
   CRootObject(/* some parameters */)
   {
      /* ... */
   }

   // some overriden methods, specific to root object
   void virtual M_J()
   {
      // implementation that can call M_J() from CObject
   }

private:
   // some root object data
};

class CAnyObject : public CObject
{
public:
   CAnyObject(/* some parameters */, const IObject* pParent) : m_pParent(pParent)
   {
      /* ... */
   }

   // some overriden methods, specific to any object
   void virtual M_J()
   {
      // implementation that can call M_J() from CObject
   }

private:
   const IObject* m_pParent;

   // some data that holds information about difference with parent object
};


class CObjectStorage
{
public:
   IObject* GetObject(/* some parameters */, IObject pParent)
   {
      IObject* pObject = nullptr;
      if (pParent == nullptr)
      {
         if (m_pRoot != nullptr)
         {
            // throw exception about second root object
         }
         pObject = new CRootObject(/* some parameters */);
         m_pRoot = pObject;
      }
      else
      {
         // if found in vector by parameters, then return existing pointer

         pObject = new CAnyObject(/* some parameters */, pParent);
      }

      m_vecObjects.push_back(pObject);

      return pObject;
   }

   ~CObjectStorage()
   {
      for (auto pObject : m_vecObjects)
      {
         delete pObject;
      }
   }

private:
   std::vector<IObject*> m_vecObjects;
   IObject* m_pRoot;
};

int main()
{
   CObjectStorage storage;

   IObject* pRoot = storage.GetObject(/* some parameters */, nullptr);
   IObject* pObj1 = storage.GetObject(/* some parameters */, pRoot);
   IObject* pObj2 = storage.GetObject(/* some parameters */, pRoot);
   IObject* pObj3 = storage.GetObject(/* some parameters */, pObj2);

   pObj3->M_1();

   return 0;
}
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Аватара пользователя
Сионист
Сообщения: 1211
Зарегистрирован: 31 мар 2014, 06:18

Romeo писал(а):fgsdgsdghsh
Вы когда в такси садитесь, вам советуют заехать вместо своего дома к друзьям? Считайте, что это требование. В крайнем случае пусть это будет закрытый класс-член. Только зачем?
Писать можно на чём угодно, но зачем же так себя ограничивать? Пиши на c.
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Сионист, вот это именно то, о чём я говорил. Я тебе помочь хочу, а ты критикуешь мою арихитектуру. Глупый, я же тебя хочу научить, как это делается в коммерческом коде, а не как в твоей лабе универовской. Уровень другой, понимаешь? Лучше бы конкретно по коду указал, что тебя смущает и я бы объяснил, чем именно мой вариант будет лучше.

К примеру хранить все объекты не в статических данных внутри класса, а в отдельном классе лучше хотя бы потому, что увеличиваем гибкость. Если вдруг потребуется создать два независимых набора объектов у каждого из которых будет свой эталон, то в моём случае достаточно будет всего лишь создать два разных объекта типа "хранилища". А твой же код придётся вообще выбросить и написать заново. Мотивация понятна?

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

Ну и если уж ты хочешь поиграть в ассоциации с такси, то я, пожалуй, поправлю немного тебя. У тебя сейчас такси едет на крыше и таксист гребёт вёслами. Стоило мне перевернуть автомобиль, поставить на колёса и отобрать у таксиста вёсла, как ты сразу же всполошился, так как уже пригрел место в салоне на крыше, а сиденье мало того, что холодное, так ещё и непривычно мягкое.

Давай так. Если ты готов обсуждать архитектуру и приводить конкретные доводы почему так, а не этак, то мы продолжим дискуссию. Я не исключаю, что мой набросок требует доработки, так как я точно не знаю особенностей "отношений" между элементами множества. Но в любом случае твои слова должны быть аргументированы, а не посвящены никому не нужной игре в ассоциации.

Если же аргументации никакой не будет, и ты вместо этого будешь лить воду, то я просто закрою тему. Флуд я не поощряю.

И, кстати, Оксалайя права. Было бы очень интересно посмотреть на твой код. Можешь выложить? Может тогда и никаких дополнительных объяснений по поводу "отношений" не понадобится.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Закрыто