L B:
- Well I'll offer a real life solution, as TheIdeasMan suggested.
TheIdeasMan:
- Let me assure you that I [think i] know exactly what I'm doing with my code. I know what I want, and I'll now try to explain what that is: A system that makes programming larger systems easier; it must eliminate some of the most common C++ programming quirks that annoy me. (Yes, very ego-centric of me)
First some key points in the design.
1. No dependencies on global variables allowed.
- A: We create a map that is local to a chain of classes that have created each other and passed the data. Any class inheriting Vault will have access to a specific map that is shared with a few other classes that inherit Vault. Thus the "create" function comes in the playing field, it creates a new map and thus starts a new
chain of data flow.
2. The ability to dynamically add or remove classes without too much work.
- A: Imagine class A, B, C,... Z. Z requires data stores by A, but A is destroyed (deleted) when it builds B (through delete this;). A stores its item as a pointer in the map. Class X2 needs to be added, standard procedure would be to pass the map ("Global-local" data) through the constructors. This is extremely tedious and doesn't give me any breathing space. Therefore, we make every class inherit from Vault. Every class then uses a build function which automagically passes the map WITHOUT you doing anything but inherit from Vault! The map is accessible from any Vault-inheriting class (just like in parameter passing), that is actually "built" (build function) by a class that has a Vault.
3. Cohesion
- A: The reinterpret casts are only performed to dereference map items. If a class Z needs to access data in A, then there will be coupling if Z knows through A what type the object needs to be. Luckily, we only need to reinterpret_cast once from the map's void ptr to Z's internal data pointer (which has a type). I put this in a templated protected member functions like so:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
// This one takes a pointer and stores an address in it, does not require explicit template arguments.
template <typename POINTER_TYPE, typename KEY_TYPE>
void fetch(POINTER_TYPE &ptr, KEY_TYPE key)
{
ptr = reinterpret_cast<POINTER_TYPE>((*m_map)[std::abs(static_cast<signed int>(key))]);
}
// This one returns the pointer, needs explicit template argument for POINTER_TYPE
template <typename POINTER_TYPE, typename KEY_TYPE>
POINTER_TYPE fetch(KEY_TYPE key)
{
return reinterpret_cast<POINTER_TYPE>((*m_map)[std::abs(static_cast<signed int>(key))]);
}
|
These functions are inherited by inheriting Vault, this means anything that doesn't inherit Vault has no access whatsoever to the map.
Q: Why the heck do you use std::abs in a signed int map?!
A: -1, -2,... contain system objects (Flare for signalling, object counter, mutexes..)
4. Allowing an inheritance chain to share the data as well:
- A: Virtual inheritance, all object handle themselves yet they are intertwined. I really like that concept.
Anywaysze,.. I've slept over the design and came up with using a proxy class. This solves my virtual inheritance problem whilst not having to pass object through constructors!
I needed to change the create and build function. Proxy class definition is all the way down.
(Post's too long, even tho it's under 8192 chars.)