License : Creative Commons Attribution 4.0 International (CC BY-NC-SA 4.0)
Copyright : Hervé Frezza-Buet, CentraleSupelec
Last modified : April 9, 2024 11:25
Link to the source : block.md

Table of contents

Textual formulas (Labwork about inheritance)

Introduction

The probem

This labwork focuses on the power of inheritance in the software design. Here, we adress the problem of writing formulas in text mode.

The following math formula

A nice formula
A nice formula

can be written as the following text

 /   /   x + 1      \                
 |   |---------- + 3| * (2x + 1)     
 |   \ x - 2001     /                
 |  ----------------------------- = 5
 |             3x + 2                
<                                    
 |                                   
 |        x + 5                      
 |  2x + ------- = 12                
 \        x + 8                      

The difficuty is to write this text line by line, since, for example, one of these lines is (we use . to represent spaces for the sake of illustration)

.|...\.x.-.2001...../................ 

A smart solution is to use inheritance. We will not set up a grid of characters in which we will draw the formulas. Rather, we will as every drawable stuff to be able to print one of its line. Such drawable thing will be called a block.

So printing a block on the terminal consists of asking it to print its lines one after the others.

We will give a number to each line of a block. One of this line, called the reference line will have number 0. The lines above the reference line have negative numbers, while the lines below will have positive numbers. For example, the line numbers of our formula could be

-5:  /   /   x + 1      \                
-4:  |   |---------- + 3| * (2x + 1)     
-3:  |   \ x - 2001     /                
-2:  |  ----------------------------- = 5
-1:  |             3x + 2                
 0: <                                    
 1:  |                                   
 2:  |        x + 5                      
 3:  |  2x + ------- = 12                
 4:  \        x + 8                      

We will print line numbers in this labwork, for the sake of illustration (and debugging). So when we ask this block to print its line number -3, it prints (spaces are represented by dots).

-3: .|...\.x.-.2001...../................ 

Saying that a block, whatever it is, is something that knows hos to print each of its lines, is an approach that has an inheritence flavor… this is what this labork will exploit.

Getting started

Download the blocks.tar.gz archive. It contains numbered test files. Hereafter, you will be asked to fill blk*.cpp, sometimes blk*.hpp files as well (the file blk.hpp includes all of them at once), and make sure that the test file corresponding to the question you are addressing compiles and runs fine.

For example, compiling and running the first test is done by

mylogin@mymachine:~$ g++ -o test -I. -std=c++17 -pedantic -Wall blk*.cpp test-001-debug.cpp
mylogin@mymachine:~$ ./test

You can find the solutions in the blocks-solution.tar.gz archive, but you are really encouraged not to use it. Making errors, and understanding why, is the way to learn C++. Ask the teachers if you get stucked.

Abstract blocks and debug blocks

A block is defined by its width and height, but also by the position of a reference point.

Definitions and notations for a block
Definitions and notations for a block

Let us start by the implementation of a block for debugging. Read the blockBlock.hpp and the blockDebug.hpp files and fill the blockBlock.cpp and the blockDebug.cpp files in order to have test test-001-debug.cpp work correctly.

Core block manipulators

All the formulas rendering is based on 3 kinds of manipulations. They consist in building a block from one, or two other blocks. A manipulator block holds a reference to the block (or the two blocks) it handles, this is why we use share pointers. Indeed, a block can be handled by more than one manipulator.

We define 3 manipulators. The first two, beside and over handle two blocks. They build up a block that displays the two blocks handled, horizontally and vertically. Note the use of reference point that define how the blocks are aligned in both case, and note where is the reference point of the manipulator block.

The beside block binary manipulator
The beside block binary manipulator
The over block binary manipulator
The over block binary manipulator

Last manipulator is unary. It handles a single block, but behaves as if the reference point of that block were elsewhere. It is the move_ref manipulator. The change of reference point enables to control how blocks are aligned, if the default behavior of over and beside is not suitable.

The move_ref block unary manipulator
The move_ref block unary manipulator

The beside block

Read the blkBeside.hpp file. Implement blkBeside.cpp in order to have test test-002-001-beside.cpp work correctly. Use the following figure to implement the computation of sizes and references.

Computation hints for beside manipulator
Computation hints for beside manipulator

The over block

Read the blkOver.hpp file. Implement the blkOver.hpp and blkOver.cpp files in order to have test test-002-002-over.cpp work correctly. Use the following figure to implement the computation of sizes and references.

Computation hints for over manipulator
Computation hints for over manipulator

The move_ref block

Read the blkMoveRef.hpp file. Implement the blkMoveRef.hpp and blkMoveRef.cpp files in order to have test test-002-003-moveref.cpp work correctly. No computation hint here… this is surprisingly easy.

First implementations

The textual expressions.

Write the blkText.hpp and blkText.cpp files in order toimplement textual blocks. Make test-003-text.cpp compile and work fine.

Some operators

Write the blkOperators.hpp and blkOperators.cpp files in order to implement basic operators. Make test-004-operators.cpp compile and work fine.

There is no need for new class definitions here, only apply what we have already defined.

Hervé Frezza-Buet,