Проблема 1 не легко решается (на самом деле я думаю, что это невозможно исправить).Любопытно, что повторяющаяся идея шаблона ближе всего подходит к ее решению, потому что базовый класс кодирует производный тип, но вам придется добавить базу к каждому производному классу, если вы действительно настаиваете на знании производного типа при создании базы.
Если вы не возражаете против выполнения ваших реальных операций (я имею в виду не только бухгалтерии) или изучения списка вне конструктора или деструктора каждого объекта, вы можете (ре) построить только минимальный списоккогда операция должна быть выполнена.Это дает вам возможность использовать полностью сконструированный объект и упрощает решение проблемы 2.
Вы могли бы сделать это, сначала имея список объектов, которые были построены, но не включены«полный» список.И «полный» список будет содержать два указателя на построенный объект.Одним из них является указатель на базовый класс, который вы будете хранить в конструкторе Observable
, возможно, несколько раз при создании одного объекта.Другой - void *
, указывающий на наиболее производную часть объекта - используйте dynamic_cast<void *>
, чтобы получить это - и используется, чтобы убедиться, что каждый объект появляется только один раз в списке.
Когда объект уничтожен, если у него есть несколько Observable
баз, каждая попытается удалить себя из списков, а когда дело доходит до полного списка, удастся выполнить только одну, но это нормально, потому что каждая из них одинаково хороша какпроизвольная основа этого объекта.
Ниже следует некоторый код.
Ваш полный список объектов, итеративный, настолько простой, насколько позволяет std::map
.(Каждый void *
и каждый Observable *
уникален, но в качестве ключа используется Observable *
, так что запись в деструкторе Observable
легко удалить.)
typedef std::map<Observable *, void *> AllObjects;
AllObjects allObjects;
ИВаш список объектов, которые были построены, но еще не добавлены в allObjects
:
std::set<Observable *> recentlyConstructedObjects;
В конструкторе Observable
добавьте новый объект в список ожидающих объектов:
recentlyConstructedObjects.insert(this);
В деструкторе Observable
удалите объект:
// 'this' may not be a valid key, if the object is in 'allObjects'.
recentlyConstructedObjects.erase(this);
// 'this' may not be a valid key, if the object is in 'recentlyConstructedObjects',
// or this object has another Observable base object and that one got used instead.
allObjects.erase(this);
Прежде чем вы приступите к работе, обновите allObjects
, если после этого были построены какие-либо объектыв последний раз оно обновлялось:
if(!recentlyConstructedObjects.empty()) {
std::map<void *, Observable *> newObjects;
for(std::set<Observable *>::const_iterator it = recentlyConstructedObjects.begin(); it != recentlyConstructedObjects.end(); ++it)
allObjectsRev[dynamic_cast<void *>(*it)] = *it;
for(std::map<void *, Observable *>::const_iterator it = newObjects.begin(); it != newObjects.end(); ++it)
allObjects[it->second] = it->first;
recentlyConstructedObjects.clear();
}
И теперь вы можете посетить каждый объект по одному разу:
for(std::map<Observable *,void *>::const_iterator it = allObjects.begin(); it != allObjects.end(); ++it) {
// you can dynamic_cast<whatever *>(it->first) to see what type of thing it is
//
// it->second is good as a key, uniquely identifying the object
}
Ну ... теперь, когда я все это написал, яне уверен, решит ли это вашу проблему.Тем не менее было интересно рассмотреть.
(Эта идея решит одну из проблем с любопытным повторяющимся шаблоном, а именно, что у вас есть много базовых объектов на производный объект, и из-за этого сложнее распутать. (К сожалению,нет решения для большого количества базовых классов, извините.) Из-за использования dynamic_cast
, конечно, не очень полезно, если вы вызываете его во время конструирования объекта, что, конечно, является преимуществом любопытно повторяющейся вещи: вы знаете производный тип во время строительства базы.
(Таким образом, если вы идете с этим стилем решения, И вы в порядке с выполнением операций вне стадии строительства / разрушения, И вы неНе говоря уже о (нескольких) базовых классах, занимающих место, вы, возможно, могли бы заставить каждый конструктор базы хранить некоторую специфичную для класса информацию - используя, возможно, typeid
или черты - и объединять их вместе, когда вы строите большой список.должно быть простым, так как вы будете знать, какая базаобъекты соответствуют одному и тому же производному объекту.В зависимости от того, что вы пытаетесь сделать, это может помочь вам с проблемой 3.)