this section shouldn't be visible
Just before the holiday, another mail. As already announced, I just want to use more controls for output, on the other hand, manual cleanup is still necessary so far. I explained that this is not necessary thanks to RAII and can be prevented by C++ itself in the post RAII - mouse pointer for VCL + FMX. So in this post I want to start to design a RAII wrapper. Further controls I will look at in the next post.
With our RAII- Wrapper the creation of the concrete auxiliary classes and the assignment should be taken over by the specialization of a template method Activate(), and the necessary temporary variable should be stored as a private element. This is used to restore the previous state when leaving the scope.
This results in the following class.
later add a link to RAII - Mpointer for VCL + FMX
class TMyStreamWrapper {
private:
std::ostream& str;
std::streambuf* old;
public:
TMyStreamWrapper(std::ostream& ref) : str(ref) { old = 0; }
~TMyStreamWrapper(void) {
if(old != 0) delete str.rdbuf(old);
}
void Reset(void) {
if(old != 0) {
delete str.rdbuf(old);
old = 0;
}
}
template <typename ty> void Activate(ty* element);
operator std::ostream& (void) { return str; };
private: // pre C++11
TMyStreamWrapper(TMyStreamWrapper const& ref) : str(ref.str) { };
void Check(void) { if(old != 0) throw std::runtime_error("Attention, prior activation"); }
};
template<>
inline void TMyStreamWrapper::Activate<std::streambuf>(std::streambuf* buff) {
Check();
old = str.rdbuf(buff);
}
#if defined BUILD_WITH_VCL || defined BUILD_WITH_FMX
template<>
inline void TMyStreamWrapper::Activate<TMemo>(TMemo* element) {
Check();
old = str.rdbuf(new MyMemoStreamBuf(element));
}
#endif
template<typename ty>
inline void TMyStreamWrapper::Activate(ty* element) {
throw std::runtime_error("no specification for TMyStreamWrapper::Activate");
return;
}
Let's take a closer look at the class "TMyStreamWrapper". We define two data elements. The first one is a reference to an ostream "str", thus also to any class derived from it, and represents the stream to be redirected. Second, we define an "old" pointer to the previous streambuf element of the stream, which is cached. In the constructor, we pass a reference to an ostream as a parameter. This is to be reassigned. Since it is a reference, the assignment must be made to the data element "str" in the constructor list, i.e. before the opening curly bracket of the function block. The second data element "old" is initialized with 0. I have decided here for compatibility with C++98, should you only use a current compiler, this can and should of course be nullptr. Or you can use the conditional compilation to distinguish between the assignment of 0 and nullptr.
In the destructor the previous cached data element "old" is used to restore the previous state. For this purpose it is checked whether the data element is not equal to 0,
and then the previous state is restored by calling rdbuf() and the passed data element is deleted.
The method Reset() resets the previous state and deletes the previously passed streambuf object. This makes it possible to make a new assignment.
The template Activate() takes over this assignment and forms the most important part of it. There are later the specializations, which are implemented as explicit inline methods below the class. Specializations extend the concept of the templates considerably and provide us with many new possibilities. But it is amazing that many do not use them.
What is important is the method that takes a pointer to a streambuf object, and thus can take any object derived from streambuf. It is a universal access to this wrapper. The final part is the general template definition (without specialization), but this will cause a runtime error. Everything between these two can be added later, in the above listing it is the redirection to a memo field already done by us using the class MyMemoStreamBuf from the post Use of standard streams for output in memo fields.
The function operator is used to be able to use the redirected stream from outside. Therefore a reference to ostream is simply returned here, with the data element "str".
The check method is used to prevent multiple assignment during activation. If the data element "old" is not equal to 0, a runtime error is triggered here.
Finally, the copy constructor. With C++11 I could simply delete it, but because I wanted to stay compatible to older compilers, I decided to use the well known trick to prevent that a copy of the instance is initiated from outside. Therefore the copy constructor is simply moved to the private part, so that only the methods of the class itself could create copies. Again, if you only use a current compiler, please delete the copy constructor.
Now we can use this wrapper to undo the assignment at the end of the program and make sure that no errors occur.
Attention, add link to use standard streams for output in memo fields
Keine Kommentare
3 days
8 Participants
3 Days
8 Participants
In this seminar you will get a compact introduction to the latest version of C++Builder (currently 10.3.3). C++Builder is a cross-platform development tool that allows you to develop high-performance, native applications for the target platforms Windows (32bit, 64bit), Mac OS (32bit), iOS and Android.
5 Days
8 Participants
As the title of the course says, this course is about developing native applications for mobile devices (app) with C++Builder (currently 10.3.3).
2 Days
8 Participants
This course is designed for C++ developers who want to use the C++Builder and deepen their knowledge. In addition to using the components and the properties of the C++ language, it is especially important to combine both in a sensible way.
3 Days
8 Participants
This seminar is aimed at C++ programmers who want to extend access to databases in their applications. This seminar explains the main components of the C++ Builder for database access, but also shows how to integrate them into a clean application architecture.
3 Days
8 Participants
This seminar is aimed at C++ programmers who have gained experience with the database components of the C++ Builder and now want to develop scalable database applications. In this seminar the importance of ANSI C++ - interfaces between the business logic of an application and the database is shown.
3 Days
6 Participants
This course is aimed at software developers who want to learn the elements of the C programming language as a basis for a later entry into object-oriented programming with C++.
3 Days
8 Participants
This seminar is aimed at programmers who want to switch from C to C++. The most important extensions of the C++ language and the differences to C are discussed in detail.
3 Days
5 Participants
This seminar is aimed at programmers who want to switch from C to C++. The most important extensions of the C++ language and the differences to C are discussed in detail.
5 Days
8 Participants
We were often asked if we could do a training "with everything". A larger example, starting with an idea, developing an architecture from it, and then implementing it independently in C++. Just use the extensions without letting them determine our structure and architecture, and if possible, combine this with developing access for mobile applications.
5 Days
8 Participants
In this seminar you will learn which Open Source tools you can use for your daily work with the current C++ Builder 10.3.3. This includes solutions for documenting, metrics, code analysis and code management.
2 Days
6 Participants