This is typically the kind of thing I'd do with purely dynamic typing, so yeah, variants.
"And as long as a sack of shit is not a good thing to be, chivalry will never die."Of course, when it comes to simple cases like collections, templates are definitely the best.
edited 6th Jun '11 6:55:18 AM by Yej
Da Rules excuse all the inaccuracy in the world. Listen to them, not me.From a purely OOP point of view, collections of objects derived from a base type.
Let's say I have a game world. I have a master list of game objects in that world that I iterate through. The Game Object type may have several types derived from it, such as Creature, Item, Room, etc. The Creature object may have Player and NPC subtypes. The Item object may have Armor, Weapon, and Food subtypes. All are derived from a base type and I can construct a container object (linked list, whatever) with that base type, with the actual type of any given object determined at runtime.
Example 2. I have a user interface built up from various UI element objects. Top level is "Frame", defining basic attributes like coordinates, border type, visibility, alpha, scaling, etc. From this class I derive "Dialog", "UI Panel", "Action Bar", "Unit Frame", etc. Again, a completely legit use of runtime dynamic typing.
"It's Occam's Shuriken! If the answer is elusive, never rule out ninjas!"To me, this is a bad example: You shouldn't have to use anything more dynamic than simple virtual function calls here. No RTTI, including dynamic_cast.
edited 6th Jun '11 7:20:26 AM by Medinoc
"And as long as a sack of shit is not a good thing to be, chivalry will never die."I know what type hierarchies are, but that's not what I thought he meant. I interpreted it to mean constructing an entire type definition at runtime, and then instantiating it, despite the fact the compiler doesn't even know it exists.
Da Rules excuse all the inaccuracy in the world. Listen to them, not me.If I make I game which I want to be scriptable, that's what I do (interaction between a real scripting language and the static infrastructure; I have a love/hate relationship with it after having to work with a program written in TCL + C++, with TCLCL as an intermediate layer).
edited 6th Jun '11 7:24:40 AM by Medinoc
"And as long as a sack of shit is not a good thing to be, chivalry will never die."Perhaps I misunderstand what is being discussed, then. I'm somewhat fuzzy on the more elaborate details of instantiation, coming from a procedural background as I do.
I do a lot of dynamic typing in VBA but, as I said above, that's usually for handling of different Object classes or database elements using Variants.
World of Warcraft uses a scripting language called Lua to write addon code. The game application is itself written in C++ and there's a built-in Lua interpreter that handles all the addons. So, that's a case where you do have entire classes being created "at runtime", depending on your definition of runtime. Even within the Lua environment, you can construct frame objects on the fly rather than statically in XML.
edited 6th Jun '11 7:28:45 AM by Fighteer
"It's Occam's Shuriken! If the answer is elusive, never rule out ninjas!"(first part) Ah, you're talking of dynamically instantiating stuff. To my knowledge, this can't be done in C++ with RTTI. But you can do it without RTTI by creating a map of strings to function pointers: The map will be filled at run-time, but the code to fill it must be hard-coded.
std::map<std::string, CREATEPROC> g_createProcs;
template<class T> Base* Create(void) { return new T(); }
int main(void) {
g_createProcs.Add("Foo", Create<Foo>); g_createProcs.Add("Bar", Create<Bar>); g_createProcs.Add("Baz", Create<Baz>);
...
}
(second part) Exactly what I was talking about.
edited 6th Jun '11 7:53:39 AM by Medinoc
"And as long as a sack of shit is not a good thing to be, chivalry will never die."edited 6th Jun '11 7:54:22 AM by Medinoc
"And as long as a sack of shit is not a good thing to be, chivalry will never die."If you want to generate code at run time, you're going to have to bundle some sort of interpreter or compiler. There's no real way to get around that. If the program is itself running in an interpreter or JIT compiler, then you can use that instead.
Blind Final Fantasy 6 Let's PlayJust had a thought. Remember that I'm a bit fuzzy on the C++ syntax due to not using it in decades, but couldn't you get a Variant by making a class with two elements: data and type? You'd need constructors and operators for each distinct type that the Variant would be able to handle; these set the type value, allocate any needed memory, and (if needed) cast the data member to a pointer of the desired type.
You could manage typecasting with the aforementioned overloaded operators, only throwing an exception if you tried to operate on data of fundamentally incompatible types.
In fact, I'd swear this is one of the textbook examples we used in my C++ class, lo those many years ago.
edited 6th Jun '11 9:35:26 AM by Fighteer
"It's Occam's Shuriken! If the answer is elusive, never rule out ninjas!"I'm still not sure what you are trying to do, and why a simple
class Variant {virtual ~Variant()};
class Some Stuff : public Variant {};
vector<Variant*> vec;
won't do it. You can use typeid to determine (and compare) type during runtime.
edited 6th Jun '11 9:38:48 AM by Uchuujinsan
Pour y voir clair, il suffit souvent de changer la direction de son regard www.xkcd.com/386/That's exactly what I am talking about.
"It's Occam's Shuriken! If the answer is elusive, never rule out ninjas!"Isn't that also what a void pointer does?
Da Rules excuse all the inaccuracy in the world. Listen to them, not me.Sort of, but unless I'm a bit crazy in the head, you have to know what the void pointer is referencing; you can't assume it from the contents. You also have to dereference it before performing operations on its contents; encapsulating it in a class would handle all of that.
edited 6th Jun '11 9:48:18 AM by Fighteer
"It's Occam's Shuriken! If the answer is elusive, never rule out ninjas!"In general (if the design allows it) you wouldn't type cast though, just use virtual function calls:
class Variant {
public: *
virtual void WriteToDocument(const& document doc) = 0;
}
document targetDoc;
vector<Variant*> vec;
for(auto i = vec.begin(); i != vec.end();++i) {
i->WriteToDocument(targetDoc);
}
^^
Void pointers have no information about the location they point to, they don't even know what object is there, if any. The pointers above know what they point to, and even adapt during runtime depending on what it is.
edited 6th Jun '11 9:54:20 AM by Uchuujinsan
Pour y voir clair, il suffit souvent de changer la direction de son regard www.xkcd.com/386/There are a lot of different ways to do stuff in C++, each with their own advantages and disadvantages. It's entirely possible to simulate dynamic typing, it's just not idiomatic.
Without more information, it's impossible to tell what's the best for you.
Blind Final Fantasy 6 Let's PlayYou can hack together a lot of things within c++, with templates,macros, and operator overloading. The boost people even hacked together what basically amounts to automatic type deduction so this is possible
auto x=7;
Note, that used the C++0X syntax because I am too lazy to figure out the actual syntax for boost auto.
edited 6th Jun '11 11:11:52 AM by delta534
Couldn't you just use D at that point?
[1] This facsimile operated in part by synAC.One could but C++ has better support and is more well known than D.
^^This? I think the term "standard template library" is exclusive to C++. And yeah, the site's kind of weirdly laid out.
And I only said that because it has an auto keyword.
edited 6th Jun '11 11:31:49 AM by Tzetze
[1] This facsimile operated in part by synAC.@Uchuujinsan: Basically, I defined RTTI as "anything more elaborate than a virtual function call". My first OO language was Java, where all member functions are virtual by default, so my head-definition for RTTI was "instanceof and reflection".
I'd note that some compilers (such as Visual C++) use definitions similar to mine, in which "RTTI" is something added to the virtual function table: Usually, it includes the type name, stuff like type_id, and dynamic casts.
PS: I hate the new auto keyword because after thinking with compilers, I got used to thinking the other way around: Declare the type for the variable, and use a special new to say "same type".
such as:
derivedclass *derivedpointer;
somepointer new=(foo, bar);
derivedpointer dynamic_cast=(somepointer); //cast fails, result will be null
edited 6th Jun '11 1:09:29 PM by Medinoc
"And as long as a sack of shit is not a good thing to be, chivalry will never die."
Pseudocode:
- For each record in the query:
- Create a new document in the destination database.
- Copy each field from the record to the destination document.
- If the field is an "array" type field, read each record from the subtable into an array and copy that into the destination document.
- Save
- Close
"It's Occam's Shuriken! If the answer is elusive, never rule out ninjas!"