License : Creative Commons Attribution 4.0 International (CC BY-NC-SA 4.0)
Copyright : Hervé Frezza-Buet, CentraleSupelec
Last modified : April 19, 2024 10:22
Link to the source : block2.md

Table of contents

Improving the design of the blocks library

In this second part, only code design is considered, we will not develop any more features. Implement all the following refinements. You may encounter compiling errors, and you may need to adapt some parts of the blk*.cpp files to solve them.

Forcing the user to use the factory

In the test files, we only use factories to get expressions. For example, while auto a = blk::text("foo") builds an instance of a blk::Text kind of block, we only get an expression, which is a pointer on the general blk::Block type. In our usage, we only rely on what general blocks can offer, no more. Functions like auto a = blk::text("foo"), that builds more than a generic instance (a text here), but only returns their result as a pointer on a generic instance, are called factories.

With the current implementation, one can write

Debug d {'a', 3, 4, 2, 2};
expr  d = std::shared_ptr<Text>("foo");
Beside b {d, d};

which is not the way our classes are expected to be built, since we would recommend only to use factories as blk::debug(...) or blk::text(...).

To solve this, tag all the default blk::Block constructors and affectations as delete, and put the constructor that we have defined for the class blk::Block as a protected constructor, since only derived class need it.

For all the derived classes (as blk::Debug, blk::Over, …), tag as delete all the default constructors and affectations. Put the constructor that is defined in the private section. Factories lie blk::debug thus have to be friend of their corresponding class. You may encounter a compiling issue with std::make_shared in this case… Do you understand why ? How can you solve it ?

Hide the handling of printings

In the class blk::Block, the two methods print_line and print_inbounds_line are public. Indeed, the first needs to be called by the operator<< serialization as well as derived classes. It thus have to be protected, and the operator<< has to be declared friend to the class blk::Block to break this limited access… but this is already the case since it uses private min_line and max_line methods.

The second method, print_inbounds_line, has to be protected as well, since it only aims at being overrided by derived classes.

Make this modifications, and compile some test. You will have errors about access to protected method print_line. There is a mention of that issue in the lecture (see Class / Simple inheritance / The protected limitation work around), apply the work around presented there.

The file blocks-complete.tar.gz is a solution for all these improvements.

Implement extra features

You can design your own tools. For example, extensible delimiters (like parentheses, braces, etc…) can be defined, all inherited from the same class. Operators tha put things between parentheses, braces, can be defined. Displaying arrays of expressions, with a brace on the left, can also be defined as an operator.

Last, you can add a new unary manipulator, that places a block at the center of a predefined rectangular area. The can be used to display matrix elements, for example, so that they all appear placed in the squares of a regular grid.

Hervé Frezza-Buet,