I am working on custom lightweight UI library for my C++ project and I have question about implementing control's behavior.
Currently I have system that create instances of controls from provided files, so graphical representation, text, dimensions and other parameters are defined in external file. Regarding buttons and other interactive controls: I have base button class and for each button I am creating derived class with its own implementation of behavior related methods(onClick() etc.) see pseudo snippet:
class Button
{
public:
Button();
virtual void onClick();
};
class newButton : public Button
{
void onClick()
{}//specific implementation
};
I am looking for way to describe behavior externally(scripting language possibly) and inserting it to specific instance of base button on compile, so I won't need to create subclasses of button, and buttons/components could be completely described in external file. Any toughts or recommendations will be appreciated.
Thanks
Well I think you got another XY problem: Using run-time object polymorphism is not able to solve your wish. Although it enables C++ code to not care which specific implementation one uses, and can accept new unknown solutions at run time, these new solution still have to be compiled with an C++ compiler, and be compliant with the base class definition and C++ implementation (your compiler like gcc or MSVC) specific details of runtime polymorphism.
Since I assume you don't want that, which also makes sense and is a pattern getting popular in the C++ world (see QML or Javascript/C++ hybrids), you have some options.
Either you implement all basic behaviour building blocks in C++ (where you can of course use runtime polymorphism or even compile time polymorphism), which you then simply combine according to your UI description language at run time. To parse your so called DSL i.e. UI description language, you can use libraries like boost spirit.
How ever if you really to script the UI logic and not simply describe it, you would have to design and implement a whole programming language, which is also compatible to your C++ implementations runtime object polymorphism. Which I would find a very big and long task.
But don't dispair, that are ready solution like Javescript/C++ in the form of react native and electron using native node modules, or QML/Qt, or lua, a scripting language, specifically designed to be used in other programming languages.
Related
The DYNAMIC FACTORY pattern describes how to create a factory that
allows the creation of unanticipated products derived from the same
abstraction by storing the information about their concrete type in
external metadata
from : http://www.wirfs-brock.com/PDFs/TheDynamicFactoryPattern.pdf
The PDF says:
Configurability
. We can change the behavior of an application by just changing its configuration
information. This can be done without the need to change any source code (just change the descriptive information about the type in the metadata repository) or to restart the application (if caching is not used – if caching is used the cache will need to be flushed).
It is not possible to introduce new types to a running C++ program without modifying source code. At the very least, you'd need to write a shared library containing a factory to generate instances of the new type: but doing so is expressly rules out by the PDF:
Extensibility / Evolvability
. New product types should be easily
added without requiring neither a
new factory class nor modifying
any existing one.
This is not practical in C++.
Still, the functionality can be achieved by using metadata to guide some code writing function, then invoking the compiler (whether as a subprocess or a library) to create a shared library. This is pretty much what the languages mentioned in the PDF are doing when they use reflection and metadata to ask the virtual machine to create new class instances: it's just more normal in those language environments to need bits of the compiler/interpreter hanging around in memory, so it doesn't seem such a big step.
Yes...
Look at the Factories classes in the Qtilities Qt library.
#TonyD regarding
We can change the behavior of an application by just changing its configuration information.
It is 100% possible if you interpret the sentence in another way. What I read and understand is you change a configuration file (xml in the doc) that gets loaded to change the behaviour of the application. So perhaps your application has 2 loggers, one to file and one to a GUI. So the config file can be edited to choose one or both to be used. Thus no change of the application but the behaviour is changed. The requirement is that anything that you can configure in the file is available in the code, so to say log using network will not work since it is not implemented.
New product types should be easily added without requiring neither a new factory class nor modifying any existing one.
Yes that sounds a bit impossible. I will accept the ability to add ones without having to change the original application. Thus one should be able to add using plugins or another method and leave the application/factory/existing classes in tact and unchanged.
All of the above is supported by the example provided. Although Qtilities is a Qt library, the factories are not Qt specific.
I have been working with QT and I noticed that they took OOP to another level by implementing some new features to classes such as private slots: public slots: signals: etc... What are they doing to declare such catagories of a class? Is it compiler specific or is it simply a sort of typedef? I am guessing it's portable to major OS's since QT will run on several systems. I ask out of curiosity and to create my own subclasses to help organize and create more OOP programs. For example
class Main
{
handles:
HANDLE hWin;
threads:
HANDLE hThread;
};
And then clean inheritance would be easy by simply doing
class Dialog : handles Main
{
};
To me, it looks like people are not answering your question, they're answering something a little different. You seem to be talking about the "section tags" that just happen to be used for slots, and would like section tags for your own class sections like handles and threads. That is something that QT does by preprocessing the code before it gets sent to the compiler. It's not something you could do yourself without adding another compilation stage.
That said, it really doesn't have much of a use, except to tell the QT precompiler the sections to find it's slots in. You can't inherit them, as you appear to want to do. It just marks an area to generate introspective code on.
And you really wouldn't want to do it like that anyway. If you have separate components that you'd like to inheret, separate them into separate classes, and then make those separate classes members of your larger class that controls their interaction. If you tried to split apart a class that had different sections, there would be no way for the compiler to ensure that they didn't interact in some way that required invariants of the other pieces, because the compiler doesn't put those kinds of boundaries up on using the different members.
It is called signals and slots is implemented by the Qt meta-object compiler moc. The moc also adds an introspection system to pre-processed classes. There are also exist signal/slot implementations that don't require a special preprocessing step such as Boost.Signals and Boost.Signals2. I wouldn't consider signals and slots more or less OOP than normal message passing through function calls, but that is argumentative and not really relevant.
I was wondering if it is possible to change the logic of an application at runtime? Meybe we could replace the implementation of an abstract class with another implementation? Or maybe we could replace a shared library at runtime...
update: Suppose that I've got two implementations of function foo(x, y) and can use any of them based on strategy pattern. Now I want to know if it's possible to add a third implementation of foo(x, y) without restarting the application.
You can use a plugin (a library that you will load at runtime) that expose a new foo function.
I remember we implemented something similar at school, a calculator in which we could add new operations at runtime, without having to restart the program. See dlsym and dlopen.
Addenda
Be very careful when dlclose-ing a plugin that it is not still used in some active call stack frame. On Linux you can call many thousands of times dlopen (so you could accept not dlclose-ing plugins, with some address space leak).
Exactly, as you said "replace the implementation of an abstract class with another implementation" if by it you mean, you can use runtime polymorphism and change the instances of concrete classes with instances of another set of concrete classes.
More specifically, there is a well-known pattern called Strategy pattern exactly for this purpose. Have a look at the wiki page, as it explains this very nicely, even with a code example along with diagram.
C++ mechanism of virtual functions does not allow you to change the implementation at run-time.
However, you can implement whatever implementation change at runtime with function pointers.
Here is an article on self-modifying code that I read recently: http://mainisusuallyafunction.blogspot.com/2011/11/self-modifying-code-for-debug-tracing.html
I'm talking about ROOT's CINT.
I've been developing a game in c++ which uses Python for programming the AI. As much as I love Python, and how easy it makes programming the AI (generators and FP are really sexy), it makes non trivial algorithms run so slow.
Then I remembered I read somewhere about CINT, and how it can be embeddable. Now I need your help to decide if implement CINT as an alternate scripting system. With python I use Boost::Python, which makes it almost unpainful to expose classes and objects once you get used to it. Is there such ease with CINT?
I've written classes compiled against Root, and then accessed them directly in the interpreter. That's easy, though all such classes are expected to derive from TObject. What I don't know is if that is a cint requirement or a ROOT requirement. you might be best off asking on the RootTalk CINT Support forum
To address the questions in the comments:
The derivation from TObject can be second hand: your classes can be derived from something derived from TObject, it just has to be a TObject.
Root provides a tool (makecint) and some macros (ClassDef and ClassImp) to support integrating your code with the interpreted execution environment: write your clas deriving it from TObject; include the ClassDef macro in the header and the ClassImp macro in the source file; run makecint over the code to generate all the tedious integration nonesense, then compile your code and the generated code to a shared object (or, I presume, a dll on a windows box); start the interpreter; load the library with .L; and your class is fully integrated with the interpreted environment (tab completion will work and all that). The build can be automated with make (and presumable other tools). ##Again,## I don't know how much of this belongs to ROOT and how much to cint. But it is all open source, so you can snag and adapt what you need.
Most mature C++ projects seem to have an own reflection and attribute system, i.e for defining attributes which can be accessed by string and are automatically serializable. At least many C++ projects I participated in seemed to reinvent the wheel.
Do you know any good open source libraries for C++ which support reflection and attribute containers, specifically:
Defining RTTI and attributes via macros
Accessing RTTI and attributes via code
Automatic serialisation of attributes
Listening to attribute modifications (e.g. OnValueChanged)
There is a new project providing reflection in C++ using a totally different approach: CAMP.
https://github.com/tegesoft/camp
CAMP doesn't use a precompiler, the classes/properties/functions/... are declared manually using a syntax similar to boost.python or luabind. Of course, people can use a precompiler like gccxml or open-c++ to generate this declaration if they prefer.
It's based on pure C++ and boost headers only, and thanks to the power of template meta-programming it supports any kind of bindable entity (inheritance and strange constructors are not a problem, for example).
It is distributed under the MIT licence (previously LGPL).
This is what you get when C++ meets Reflection:
Whatever you choose, it'll probably have horrible macros, hard to debug code or weird build steps. I've seen one system automatically generate the serialisation code from DevStudio's PDB file.
Seriously though, for small projects, it'll be easier to write save/load functions (or use streaming operators). In fact, that might hold for big projects too - it's obvious what's going on and you'd usually need to change code anyway if the structure changes.
You could have a look at the two tools below. I've never used either of them, so I can't tell you how (im)practical they are.
XRTTI:
Xrtti is a tool and accompanying C++ library which extends the standard runtime type system of C++ to provide a much richer set of reflection information about classes and methods to manipulate these classes and their members.
OpenC++:
OpenC++ is C++ frontend library (lexer+parser+DOM/MOP) and source-to-source translator. OpenC++ enables development of C++ language tools, extensions, domain specific compiler optimizations and runtime metaobject protocols.
I looked at these things for quite a while but they tend to be very heavy-handed. They might prevent you from using inheritance, or having strange constructors etc etc. In the end they ended up being too much of a burden instead of a convenience.
This approach for exposing members that I now use is quite lightweight and lets you explore a class for serialization or setting all fields called "x" to 0, for example. It's also statically determined so is very very fast. No layers of library code or code-gen to worry about messing with the build process. It generalises to hierarchies of nested types.
Set your editor up with some macros to automate writing some of these things.
struct point
{
int x;
int y;
// add this to your classes
template <typename Visitor>
void visit(Visitor v)
{
v->visit(x, "x");
v->visit(y, "y");
}
};
/** Outputs any type to standard output in key=value format */
struct stdout_visitor
{
template <typename T>
void visit(const T& rhs)
{
rhs.visit(this);
}
template <typename Scalar>
void visit (const Scalar& s, const char* name)
{
std::cout << name << " = " << s << " ";
}
}
This is a notorious weakness of the C++ language in general because the things that would need to be standardized to make reflection implementations portable and worthwhile aren't standard. Calling conventions, object layouts, and symbol mangling come to mind, but there are others as well.
The lack of direction from the standard means that compiler implementers will do some things differently, which means that very few people have the motivation to write a portable reflection library, which means that people who need reflection re-invent the wheel, but only just enough for what they need. This happens ad infinitum, and here we are.
Looked at this for a while too. The current easiest solution seems to be BOOST_FUSION_ADAPT_STRUCT. Practically once you have a library/header you only need to add your struct fields into the BOOST_FUSION_ADAPT_STRUCT() macro, as the last segment of the code shows. Yes it has restrictions many other people have mentioned. And it does not support listeners directly.
The other promising solutions I looked into are
CAMP and XRTTI/gccxml, however both seem to be a hurdle to bring external tools dependency into your project.
Years ago I used perl c2ph/pstruct to dump the meta info from the output of gcc -gstabs, that is less intrusive but needs more work though it worked perfectly for me.
Regarding the boost/__cxa approach, once you figure out all the small details, adding/changing structs or fields is simple to maintain. we currently use it to build a custom types binding layer on top of dbus, to serialize the API and hide the transport/RPC details for a managed object service subsystem.
Not a general one but QT supports this via a meta compiler, and is GPL.
My understanding from talking to the QT people was that this isn't possible with pure C++, hence the need for the moc.
Automatic introspection/reflection toolkit. Use meta compiler like Qt's and adding meta information directly into object files. Intuitive easy to use. No external dependencies. Even allow automatically reflect std::string and then use it in scripts. Please visit IDK