Why do we need run time class information in MFC? What is use of DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC?
It was the way RTTI was implemented in the very early times of the MFC and C++.
This mechanism is used to have a specific "type" (a pointer to a CRuntimeClass) and to create instances of it. I.e. the Document/Frame/View model is using such runtime classes in the document templates. (specially DECLARE/IMPLEMENT_DYNAMIC).
Also the dynamic serialization stuff of CArchive is using this runtime class objects.
Related
I am trying to implement a system where I have a template class which implements a Serializable interface.
Right now, the interface contains serialize/deserialize methods while the template Setting class has get/set, and private members settingName, settingValue and a template function T adaptType() to adapt string to correct type using the >> operator (https://gist.github.com/mark-d-holmberg/862733). The file also contains a custom struct with << and >> operators overloaded for everything to work.
Settings are serialized in form of settingName:settingValue or settingName:val1;val2;val3 in case of the struct.
There are two problems I'm facing with this design:
I want to hold all these setting objects in a map<string, ISerializable*(?)> to access them but then I can't call other functions get/set on these objects because the interface doesn't define the methods (they must be in Setting class because their type depends on the template type), if I switch the second type in map to template class, I must define a concrete type
When deserializing there's no way to know which type it is and ISerializable can't be instantiated since it's an abstract class, again I need to know which type I'm deserializing and instantiate the Setting class with appropriate type
Is there a better way to design this or something I'm missing, note that I am not very proficient with c++
Bit of a background for the problem:
I'm working on an embedded device where settings need to be loaded/saved to flash memory but there's also another framework running on the device which holds these settings in RAM and serves them on a webserver to be edited, I cannot change this part. My goal is to manually save these settings to my custom class that manages settings and save/load to flash so it is persistent between reboots and synced with the web framework.
Any help or advice is welcome
As far as I understand your problem it is similar to what the Oops library is doing. It creates a Type Descriptor class for all types having similar functionality: giving some description of the type and provide text and binary serialization for them. It is also designed to handle configuration, so it even may help to solve your problem.
It worth to have a look at least for getting some ideas: https://bitbucket.org/barczpe/oops
DECLARE_DYNCREATE provides exactly the same feature of DECLARE_DYNAMIC along with its dynamic object creation ability. Then why should anyone use DECLARE_DYNAMIC instead of DECLARE_DYNCREATE?
The macros are documented to provide different functionality.
DECLARE_DYNAMIC:
Adds the ability to access run-time information about an object's class when deriving a class from CObject.
This provides the functionality for introspection, similar to RTTI (Run-Time Type Information) provided by C++. An application can query a CObject-derived class instance for its run-time type through the associated CRuntimeClass Structure. It is useful in situations where you need to check that an object is of a particular type, or has a specific base class type. The examples at CObject::IsKindOf should give you a good idea.
DECLARE_DYNCREATE:
Enables objects of CObject-derived classes to be created dynamically at run time.
This macro enables dynamic creation of class instances at run-time. The functionality is provided through the class factory method CRuntimeClass::CreateObject. It can be used when you need to create class instances at run-time based on the class type's string representation. An example would be a customizable GUI, that is built from an initialization file.
Both features are implemented through the same CRuntimeClass Structure, which may lead to the conclusion that they can be used interchangeably. In fact, code that uses an inappropriate macro will compile just fine, and expose the desired run-time behavior. The difference is purely semantic: The macros convey different intentions, and should be used according to the desired features, to communicate developer intent.
There's also a third related macro, DECLARE_SERIAL:
Generates the C++ header code necessary for a CObject-derived class that can be serialized.
It enables serialization of respective CObject-derived class instances, for example to a file, memory stream, or network socket. Since the deserialization process requires dynamic creation of objects from the serialized stream, it includes the functionality of DECLARE_DYNCREATE.
Put together, the following list should help you pick the right macro for your specific scenarios:
Use DECLARE_DYNAMIC if your code needs to retrieve an object's run-time type.
Use DECLARE_DYNCREATE if, in addition, you need to dynamically create class instances based on the type's string representation.
Use DECLARE_SERIAL if, in addition, you need to provide serialization support.
You're asking "why buy a Phillips screwdriver when I own a flathead?" The answer is that you should use the tool that suits your needs: if you need to drive only flathead screws, don't buy a Phillips driver. Otherwise, buy one.
If you need the features provided by DECLARE_DYNCREATE (e.g. because you're creating a view that's auto-created by the framework when a document is opened) then you should use DECLARE_DYNCREATE and if you don't and DECLARE_DYNAMIC works, you should use it.
I'm creating a C++ object serialization library. This is more towards self-learning and enhancements & I don't want to use off-the-shelf library like boost or google protocol buf.
Please share your experience or comments on good ways to go about it (like creating some encoding with tag-value etc).
I would like to start by supporting PODs followed by support to non-linear DSs.
Thanks
PS: HNY2012
If you need serialization for inter process communication, then I suggest to use some interface language (IDL or ASN.1) for defining interfaces.
So it will be easier to make support for other languages (than C++) too. And also, it will be easier to implement code/stub generator.
I have been working on something similar for the last few months. I couldn't use Boost because the task was to serialize a bunch of existing classes (huge existing codebase) and it was inappropriate to have the classes inherit from the interface which had the serialize() virtual function (we did not want multiple inheritance).
The approach taken had the following salient features:
Create a helper class for each existing class, designated with the task of serializing that particular class, and make the helper class a friend of the class being serialized. This avoids introduction of inheritance in the class being serialized, and also allows the helper class access to private variables.
Have each of the helper classes (let's call them 'serializers') register themselves into a global map. Each serializer class implements a clone() virtual function ('prototype' pattern), which allows one to retrieve a pointer to a serializer, given the name of the class, from this map. The name is obtained by using compiler-specific RTTI information. The registration into the global map is taken care of by instantiating static pointers and 'new'ing them, since static variables get created before the program starts.
A special stream object was created (derived from std::fstream), that contained template functions to serialize non-pointer, pointer, and STL data types. The stream object could only be opened in read-only or write-only modes (by design), so the same serialize() function could be used to either read from the file or write into the file, depending on the mode in which the stream was opened. Thus, there is no chance of any mismatch in the order of reading versus writing of the class members.
For every object being saved or restored, a unique tag (integer) was created based on the address of the variable and stored in a map. If the same address occurred again, only the tag was saved, not the deep-copied object itself. Thus, each object was deep copied only once into the file.
A page on the web captures some of these ideas shared above: http://www.cs.sjsu.edu/~pearce/modules/lectures/cpp/Serialization.htm. Hope that helps.
I wrote an article some years ago. Code and tools can be obsolete, but concepts can remain the same.
May be this can help you.
Run into a bit of an issue, and I'm looking for the best solution concept/theory.
I have a system that needs to use objects. Each object that the system uses has a known interface, likely implemented as an abstract class. The interfaces are known at build time, and will not change. The exact implementation to be used will vary and I have no idea ahead of time what module will be providing it. The only guarantee is that they will provide the interface. The class name and module (DLL) come from a config file or may be changed programmatically.
Now, I have all that set up at the moment using a relatively simple system, set up something like so (rewritten pseudo-code, just to show the basics):
struct ClassID
{
Module * module;
int number;
};
class Module
{
HMODULE module;
function<void * (int)> * createfunc;
static Module * Load(String filename);
IObject * CreateClass(int number)
{
return createfunc(number);
}
};
class ModuleManager
{
bool LoadModule(String filename);
IObject * CreateClass(String classname)
{
ClassID class = AvailableClasses.find(classname);
return class.module->CreateObject(class.number);
}
vector<Module*> LoadedModules;
map<String, ClassID> AvailableClasses;
};
Modules have a few exported functions to give the number of classes they provide and the names/IDs of those, which are then stored. All classes derive from IObject, which has a virtual destructor, stores the source module and has some methods to get the class' ID, what interface it implements and such.
The only issue with this is each module has to be manually loaded somewhere (listed in the config file, at the moment). I would like to avoid doing this explicitly (outside of the ModuleManager, inside that I'm not really concerned as to how it's implemented).
I would like to have a similar system without having to handle loading the modules, just create an object and (once it's all set up) it magically appears.
I believe this is similar to what COM is intended to do, in some ways. I looked into the COM system briefly, but it appears to be overkill beyond belief. I only need the classes known within my system and don't need all the other features it handles, just implementations of interfaces coming from somewhere.
My other idea is to use the registry and keep a key with all the known/registered classes and their source modules and numbers, so I can just look them up and it will appear that Manager::CreateClass finds and makes the object magically. This seems like a viable solution, but I'm not sure if it's optimal or if I'm reinventing something.
So, after all that, my question is: How to handle this? Is there an existing technology, if not, how best to set it up myself? Are there any gotchas that I should be looking out for?
COM very likely is what you want. It is very broad but you don't need to use all the functionality. For example, you don't need to require participants to register GUIDs, you can define your own mechanism for creating instances of interfaces. There are a number of templates and other mechanisms to make it easy to create COM interfaces. What's more, since it is a standard, it is easy to document the requirements.
One very important thing to bear in mind is that importing/exporting C++ objects requires all participants to be using the same compiler. If you think that ever could be a problem to you then you should use COM. If you are happy to accept that restriction then you can carry on as you are.
I don't know if any technology exists to do this.
I do know that I worked with a system very similar to this. We used XML files to describe the various classes that different modules made available. Our equivalent of ModuleManager would parse the xml files to determine what to create for the user at run time based on the class name they provided and the configuration of the system. (Requesting an object that implemented interface 'I' could give back any of objects 'A', 'B' or 'C' depending on how the system was configured.)
The big gotcha we found was that the system was very brittle and at times hard to debug/understand. Just reading through the code, it was often near impossible to see what concrete class was being instantiated. We also found that maintaining the XML created more bugs and overhead than expected.
If I was to do this again, I would keep the design pattern of exposing classes from DLL's through interfaces, but I would not try to build a central registry of classes, nor would I derive everything from a base class such as IObject.
I would instead make each module responsible for exposing its own factory functions(s) to instantiate objects.
I'm writing an ATL project and I wonder how should I create classes here.
Right now I have one class created by Add/Class/ATL Simple Object. I want to divide it to smaller classes but method from this classes should use CComPtr and have CComPtr as an argument. I can't create 'simple' c++ class because I don't have CComPtr there.
Should I create ATL classes by ATL Simple Object Wizard and then use interface for this class to call methods. Like here:
CComPtr<ITestAtlClass> tptr;
tptr.CoCreateInstance(CLSID_TestAtlClass);
tptr->test();
And should I add all public methods by Class View/ITestAtlClass/Add/Add Method?
What about constructors? Do I must initialize my class only by properties (and add them by Class View/ITestAtlClass/Add/Add Property)? And pass every com object by IUnknown interface?
Can somebody tell me how it should be done in ATL project. I will use this smaller classes internally (nobody will create this classes outside my DLL) just to make my code more readable.
I don't understand your comment that you can't use CComPtr from a simple C++ class. Can you please clarify?
I see two strategies:
build a clean C++ object model that solves the problem, and then wrap it in a thin facade layer of one or more COM objects
Use ATL classes throughout, and use CComObject<> and derivatives to instantiate and maintain these without the overhead of CoCreateInstance and the limitations of only using public interfaces.
The first one is usually much nicer, but if you're building a data-heavy object model, the second can be a useful technique.
If you have an ATL COM class called CVehicle, that derives from CComObjectRootEx<> and friends, you can instantiate it like so;
CComObject<CVehicle>* vehicle = NULL;
CComObject<CVehicle>::CreateInstance(&vehicle);
vehicle->AddRef();
// To get at any of its interfaces, use:
CComPtr<ICar> car = 0;
vehicle->QueryInterface(&car);
// And to delete object, use:
vehicle->Release();
There's also variations on CComObject<>, e.g. CComObjectStack<> that use different allocation and reference counting strategies.
As you can see, this is pretty messy. If you can explain what you mean by your comment on not being able to use CComPtr, maybe I can expand on that.