Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 1c2a9fe6 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Solution to exercise 25 updated.

parent 515808a1
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Object programming](./0-main.ipynb) - [Hands-on 8](./7b-hands-on.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#EXERCISE-21:-base-class-TestDisplay" data-toc-modified-id="EXERCISE-21:-base-class-TestDisplay-1">EXERCISE 21: base class <code>TestDisplay</code></a></span></li><li><span><a href="#EXERCISE-22:-inherit-from-TestDisplayPowerOfTwoApprox" data-toc-modified-id="EXERCISE-22:-inherit-from-TestDisplayPowerOfTwoApprox-2">EXERCISE 22: inherit from <code>TestDisplayPowerOfTwoApprox</code></a></span></li><li><span><a href="#EXERCISE-23:-Toward-a-TestDisplayContainer-class" data-toc-modified-id="EXERCISE-23:-Toward-a-TestDisplayContainer-class-3">EXERCISE 23: Toward a <code>TestDisplayContainer</code> class</a></span></li><li><span><a href="#EXERCISE-24:-dynamic-allocation-of-array" data-toc-modified-id="EXERCISE-24:-dynamic-allocation-of-array-4">EXERCISE 24: dynamic allocation of array</a></span></li><li><span><a href="#EXERCISE-25:-transform-TestDisplayContainer::Do()-into-a-free-function" data-toc-modified-id="EXERCISE-25:-transform-TestDisplayContainer::Do()-into-a-free-function-5">EXERCISE 25: transform <code>TestDisplayContainer::Do()</code> into a free function</a></span></li></ul></div>
%% Cell type:markdown id: tags:
### EXERCISE 21: base class `TestDisplay`
Create a base class `TestDisplay` from which both `TestDisplayPowerOfTwoApprox` and `TestDisplaySum` will inherit publicly.
This class:
* Should get a constructor which sets the resolution (respectively 100 or 1000 for our two derived classes)
* Should define the `RoundToInteger` enum (as protected)
* Includes a protected method named `PrintLine()` that will replace the `PrintLine()` we introduced in previous exercise.
The constructors of derived classes will of course have to be modified accordingly: so far we relied on default ones.
**Note:** Don't bother too much for the warning
```shell
warning: 'TestDisplay' has no out-of-line virtual method definitions; its vtable will be emitted in every translation unit [-Wweak-vtables]
```
that is the result of the definition of everything in a same file. If you separate declaration in a header file and definition in a source file you wouldn't get it (we'll see that in the very last part of the lecture)
%% Cell type:markdown id: tags:
### EXERCISE 22: inherit from `TestDisplayPowerOfTwoApprox`
We would like to get back former output in which we got first all outputs for 0.65, then all the ones for 0.35.
To do so, we will create two classes `TestDisplayPowerOfTwoApprox065` and `TestDisplayPowerOfTwoApprox035` that inherits from `TestDisplayPowerOfTwoApprox`.
Of course, we still abide by the DRY principle and we want to specialize only the code related to `Do()` method.
The `main()` to use:
%% Cell type:code id: tags:
``` C++17
int main(int argc, char** argv)
{
static_cast<void>(argc); // to silence warning about unused argc - don't bother
static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayPowerOfTwoApprox065 test_display_approx065(100);
for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx065.Do(nbits);
std::cout << std::endl;
TestDisplayPowerOfTwoApprox035 test_display_approx035(100);
for (int nbits = 2; nbits <= 8; nbits += 2)
test_display_approx035.Do(nbits);
std::cout << std::endl;
TestDisplaySumOfMultiply test_display_sum_of_multiply(1000);
for (int nbits = 1; nbits <= 8; ++nbits)
test_display_sum_of_multiply.Do(nbits);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
_Expected output:_
```
[With 2 bits]: 0.65 ~ 0.75 (3 / 2^2) [error = 15/100]
[With 4 bits]: 0.65 ~ 0.625 (10 / 2^4) [error = 4/100]
[With 6 bits]: 0.65 ~ 0.65625 (42 / 2^6) [error = 1/100]
[With 8 bits]: 0.65 ~ 0.648438 (166 / 2^8) [error = 0/100]
[With 2 bits]: 0.35 ~ 0.375 (3 / 2^3) [error = 7/100]
[With 4 bits]: 0.35 ~ 0.34375 (11 / 2^5) [error = 2/100]
[With 6 bits]: 0.35 ~ 0.351562 (45 / 2^7) [error = 0/100]
[With 8 bits]: 0.35 ~ 0.349609 (179 / 2^9) [error = 0/100]
[With 1 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 2965 [error = 254/1000]
[With 2 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4448 [error = 119/1000]
[With 3 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4008 [error = 8/1000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 30/1000]
[With 5 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3967 [error = 2/1000]
[With 6 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 4004 [error = 7/1000]
[With 7 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3977 [error = 0/1000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 2/1000]
```
%% Cell type:markdown id: tags:
### EXERCISE 23: Toward a `TestDisplayContainer` class
We would like to introduce an object which purpose is to store the various `TestDisplay` class and call for each of them the `Do` method.
The declaration of the class should look like:
%% Cell type:code id: tags:
``` C++17
class TestDisplayContainer
{
public:
//! Maximum number of objects that might be stored (to avoid magic number)
static constexpr std::size_t MAX_ELTS { 3ul };
//! Add a new test_display_register.
//! At each call, the item to be registered is put at the first available position and internal current_position_
//! is incremented. If the end-user attempts to register more than three items, the Error() function is called.
void Register(TestDisplay* test_display);
//! For each `TestDisplay` stored within the container, loop over all those bits and print the result on screen.
void Do(int initial_Nbit, int final_Nbit, int increment_Nbit) const;
private:
//! List of all known `TestDisplay` objects.
TestDisplay* list_[MAX_ELTS];
//! Index to place the next register object. If '3', no more object may be registered.
int current_position_ {};
};
```
%% Cell type:markdown id: tags:
You will need to add a sanity check in constructor; in case of failure use at the moment the following function:
%% Cell type:code id: tags:
``` C++17
//! Function for error handling. We will see later how to fulfill the same functionality more properly.
[[noreturn]] void Error(std::string explanation)
{
std::cout << "ERROR: " << explanation << std::endl;
exit(EXIT_FAILURE);
}
```
%% Cell type:markdown id: tags:
The `main()` to use is:
%% Cell type:code id: tags:
``` C++17
int main(int argc, char** argv)
{
static_cast<void>(argc); // to silence warning about unused argc - don't bother
static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayContainer container;
container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
container.Register(new TestDisplaySumOfMultiply(10000));
container.Do(4, 16, 4);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
_Expected result:_
[With 4 bits]: 0.65 ~ 0.625 (10/2^4) [error = 38462/1000000]
[With 8 bits]: 0.65 ~ 0.648438 (166/2^8) [error = 2404/1000000]
[With 12 bits]: 0.65 ~ 0.649902 (2662/2^12) [error = 150/1000000]
[With 16 bits]: 0.65 ~ 0.649994 (42598/2^16) [error = 9/1000000]
[With 4 bits]: 0.35 ~ 0.34375 (11/2^5) [error = 17857/1000000]
[With 8 bits]: 0.35 ~ 0.349609 (179/2^9) [error = 1116/1000000]
[With 12 bits]: 0.35 ~ 0.349976 (2867/2^13) [error = 70/1000000]
[With 16 bits]: 0.35 ~ 0.349998 (45875/2^17) [error = 4/1000000]
[With 4 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3857 [error = 299/10000]
[With 8 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3968 [error = 20/10000]
[With 12 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
[With 16 bits]: 0.65 * 3515 + 0.35 * 4832 = 3976 ~ 3975 [error = 2/10000]
%% Cell type:markdown id: tags:
**Note:** If you're using clang, you may get these warnings:
```shell
/home/dev_cpp/training_cpp/HandsOn/2-ObjectProgramming/exercise23.cpp:379:5: warning: unsafe buffer access [-Wunsafe-buffer-usage]
379 | list_[current_position_++] = test_display;
| ^~~~~
/home/dev_cpp/training_cpp/HandsOn/2-ObjectProgramming/exercise23.cpp:388:13: warning: unsafe buffer access [-Wunsafe-buffer-usage]
388 | list_[i]->Do(nbits);
```
The compiler is really right here; the code we proposed to limit the number objects is very clunky. We will improve this in the very next exercise.
%% Cell type:markdown id: tags:
### EXERCISE 24: dynamic allocation of array
Instead of setting an arbitrary size of 3, we will now add a size dynamically in `TestDisplayContainer` constructor; the internal storage will now be:
````
TestDisplay** list_;
````
meaning we will store an array of pointers (don't worry, we will see later how to avoid such monstruosities... but it is useful nonetheless to try them a bit).
Constructor must now:
* Allocate the array of `TestDisplay*` with a **capacity** given as its argument (the capacity being the number of elements that *might* be stored inside - we'll see the chosen name is not a whim).
* Keep track of the capacity (the related data attribute should be constant: we don't intend to modify the capacity of the array after construction).
* Set each element to `nullptr`.
Destructor must of course take care of deallocating properly the memory.
%% Cell type:markdown id: tags:
### EXERCISE 25: transform `TestDisplayContainer::Do()` into a free function
We probably went a bridge too far: it is useful to provide an object which contains several `TestDisplay` together, but making it take in charge the loop might not be that good an idea (in a real program you might for instance interact with this container by another mean than the pre-defined loop).
Replace the `Do()` method by a free function with signature:
Replace the `TestDisplayContainer::Do()` method by a free function with signature:
````
void Loop(int initial_Nbit, int final_Nbit, int increment_Nbit, const TestDisplayContainer& container)
````
To do so, you will need to add several methods to `TestDisplayContainer`:
- A method that returns the **size** (i.e. the number of non nullptr `TestDisplay*` stored), which will be required to loop over the relevant elements.
- A method to access the `i`-th element stored in the table. Signature might be:
````
const TestDisplay& GetElement(std::size_t i) const
````
(but others are also possible - you may prefer to return a pointer rather than a reference).
New `main()` is:
%% Cell type:code id: tags:
``` C++17
int main(int argc, char** argv)
{
static_cast<void>(argc); // to silence warning about unused argc - don't bother
static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayContainer container(3);
container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
container.Register(new TestDisplaySumOfMultiply(10000));
Loop(4, 16, 4, container);
return EXIT_SUCCESS;
}
```
%% Cell type:markdown id: tags:
[© Copyright](../COPYRIGHT.md)
......
#include <iostream>
#include <sstream> // for std::ostringstream
#include <string>
#include <cassert>
#include <cmath> // for std::round
#include <sstream>
class PowerOfTwoApprox
{
public:
//! Compute the best possible approximation of `value` with `Nbits`
PowerOfTwoApprox(int Nbits, double value);
//! \return The approximation as a floating point.
double AsDouble() const;
//! Accessor to numerator.
int GetNumerator() const;
//! Accessor to exponent.
int GetExponent() const;
/*!
* \brief Multiply the approximate representation by an integer.
*
* \param[in] coefficient Integer coefficient by which the object is multiplied.
*
* \return An approximate integer result of the multiplication.
*/
int Multiply(int coefficient) const;
private:
int numerator_ {};
int exponent_ {};
};
int PowerOfTwoApprox::GetNumerator() const
{
return numerator_;
}
int PowerOfTwoApprox::GetExponent() const
{
return exponent_;
}
//! Returns `number` * (2 ^ `exponent`)
......@@ -36,40 +82,6 @@ int MaxInt(int Nbits)
}
//! Class to group the two integers used in the approximation we define.
class PowerOfTwoApprox
{
public:
//! Compute the best possible approximation of `value` with `Nbits`
PowerOfTwoApprox(int Nbits, double value);
//! \return The approximation as a floating point.
double AsDouble() const;
//! Accessor to numerator.
int GetNumerator() const;
//! Accessor to exponent.
int GetExponent() const;
/*!
* \brief Multiply the approximate representation by an integer.
*
* \param[in] coefficient Integer coefficient by which the object is multiplied.
*
* \return An approximate integer result of the multiplication.
*/
int Multiply(int coefficient) const;
private:
int numerator_ {};
int exponent_ {};
};
//! Helper function that computes numerator and denominator.
//! You're not obliged to use a function, but this way you enforce the Don't Repeat Yourself (DRY) principle!
//! Note: could be put in the struct... but may be kept a free function as well! We will see much later
......@@ -81,13 +93,15 @@ void HelperComputePowerOf2Approx(double value, int exponent, int& numerator, int
}
//! Compute the best possible approximation of `value` with `Nbits`
PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value)
{
int max_numerator = MaxInt(Nbits);
int& numerator = numerator_;
int& exponent = exponent_;
int& numerator = numerator_; // alias!
int& exponent = exponent_;
numerator = 0;
exponent = 0;
int denominator {};
......@@ -106,31 +120,13 @@ PowerOfTwoApprox::PowerOfTwoApprox(int Nbits, double value)
double PowerOfTwoApprox::AsDouble() const
{
int denominator = TimesPowerOf2(1, exponent_);
return static_cast<double>(numerator_) / denominator;
// As we're here in a method definition the data attributes could have been kept!
// But using accessor gives more safety: it clearly states the values are only read as accessors are const.
int denominator = TimesPowerOf2(1, GetExponent());
return static_cast<double>(GetNumerator()) / denominator;
}
int PowerOfTwoApprox::GetNumerator() const
{
return numerator_;
}
int PowerOfTwoApprox::GetExponent() const
{
return exponent_;
}
int PowerOfTwoApprox::Multiply(int coefficient) const
{
return TimesPowerOf2(GetNumerator() * coefficient, -GetExponent());
}
enum class RoundToInteger { no, yes };
class TestDisplay
{
......@@ -140,13 +136,20 @@ public:
TestDisplay(int resolution);
//! To make TestDisplay an abstract class.
virtual ~TestDisplay();
virtual ~TestDisplay() = 0;
//! Get the resolution.
int GetResolution() const;
//! Pure virtual method Do().
virtual void Do(int Nbits) const = 0;
protected:
//! Convenient enum used in \a PrintLine().
enum class RoundToInteger { no, yes };
/*!
* \brief Print a line with information about error.
......@@ -162,11 +165,25 @@ protected:
private:
//! Resolution.
const int resolution_;
const int resolution_; // `const` ensures here that it is defined in the constructor!
};
void TestDisplay::PrintLine(int Nbits, double exact, double approx,
std::string optional_string1, std::string optional_string2,
RoundToInteger do_round_to_integer) const
{
int error = RoundAsInt(GetResolution() * std::fabs(exact - approx) / exact);
std::cout << "[With " << Nbits << " bits]: " << optional_string1
<< (do_round_to_integer == RoundToInteger::yes ? RoundAsInt(exact) : exact) << " ~ " << approx
<< optional_string2
<< " [error = " << error << "/" << GetResolution() << "]"
<< std::endl;
}
TestDisplay::TestDisplay(int resolution)
: resolution_(resolution)
{ }
......@@ -175,39 +192,26 @@ TestDisplay::TestDisplay(int resolution)
TestDisplay::~TestDisplay() = default;
void TestDisplay::Do(int Nbits) const
int TestDisplay::GetResolution() const
{
static_cast<void>(Nbits); // neutralize warning about unused argument at no runtime cost.
return resolution_;
}
void TestDisplay::PrintLine(int Nbits, double exact, double approx,
std::string optional_string1, std::string optional_string2,
RoundToInteger do_round_to_integer) const
{
int error = RoundAsInt(resolution_ * std::fabs(exact - approx) / exact);
std::cout << "[With " << Nbits << " bits]: " << optional_string1
<< (do_round_to_integer == RoundToInteger::yes ? RoundAsInt(exact) : exact) << " ~ " << approx
<< optional_string2
<< " [error = " << error << "/" << resolution_ << "]"
<< std::endl;
}
class TestDisplayPowerOfTwoApprox : public TestDisplay
{
public:
//! Constructor.
TestDisplayPowerOfTwoApprox(int resolution);
virtual ~TestDisplayPowerOfTwoApprox() override = default;
//! Destructor
virtual ~TestDisplayPowerOfTwoApprox() override;
//! Pure virtual method Do().
//! Display the output for the chosen `Nbits`.
virtual void Do(int Nbits) const override = 0;
protected:
//! Method in charge of the actual display.
......@@ -218,9 +222,8 @@ protected:
TestDisplayPowerOfTwoApprox::TestDisplayPowerOfTwoApprox(int resolution)
: TestDisplay(resolution)
{ }
{ }
TestDisplayPowerOfTwoApprox::~TestDisplayPowerOfTwoApprox() = default;
void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const
......@@ -228,84 +231,72 @@ void TestDisplayPowerOfTwoApprox::Display(int Nbits, double value) const
PowerOfTwoApprox approximation(Nbits, value);
const double approx = approximation.AsDouble();
std::ostringstream oconv;
oconv << " (" << approximation.GetNumerator() << "/2^" << approximation.GetExponent() << ")";
PrintLine(Nbits, value, approx, "", oconv.str());
oconv << " (" << approximation.GetNumerator() << " / 2^" << approximation.GetExponent() << ")";
PrintLine(Nbits, value, approx, "", oconv.str(), RoundToInteger::no);
}
class TestDisplayPowerOfTwoApprox065 : public TestDisplayPowerOfTwoApprox
{
public:
//! Constructor.
TestDisplayPowerOfTwoApprox065(int resolution);
//! Destructor,
~TestDisplayPowerOfTwoApprox065() override;
//! Display the output for the chosen `Nbits`.
void Do(int Nbits) const override;
};
TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution)
: TestDisplayPowerOfTwoApprox(resolution)
{ }
TestDisplayPowerOfTwoApprox065(int resolution);
TestDisplayPowerOfTwoApprox065::~TestDisplayPowerOfTwoApprox065() = default;
virtual ~TestDisplayPowerOfTwoApprox065() override = default;
void Do(int Nbits) const override;
void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const
{
Display(Nbits, 0.65);
}
};
class TestDisplayPowerOfTwoApprox035 : public TestDisplayPowerOfTwoApprox
{
public:
//! Constructor.
TestDisplayPowerOfTwoApprox035(int resolution);
//! Destructor,
~TestDisplayPowerOfTwoApprox035() override;
//! Display the output for the chosen `Nbits`.
virtual ~TestDisplayPowerOfTwoApprox035() override = default;
void Do(int Nbits) const override;
};
TestDisplayPowerOfTwoApprox065::TestDisplayPowerOfTwoApprox065(int resolution)
: TestDisplayPowerOfTwoApprox(resolution)
{ }
TestDisplayPowerOfTwoApprox035::TestDisplayPowerOfTwoApprox035(int resolution)
: TestDisplayPowerOfTwoApprox(resolution)
{ }
TestDisplayPowerOfTwoApprox035::~TestDisplayPowerOfTwoApprox035() = default;
void TestDisplayPowerOfTwoApprox065::Do(int Nbits) const
{
Display(Nbits, 0.65);
}
void TestDisplayPowerOfTwoApprox035::Do(int Nbits) const
{
Display(Nbits, 0.35);
Display(Nbits, 0.35);
}
//! Multiply an approximated value by an integer.
int PowerOfTwoApprox::Multiply(int coefficient) const
{
return TimesPowerOf2(GetNumerator() * coefficient, -GetExponent());
}
class TestDisplaySumOfMultiply : public TestDisplay
{
public:
//! Constructor.
TestDisplaySumOfMultiply(int resolution);
//! To make the class a concrete one.
virtual ~TestDisplaySumOfMultiply() override;
//! Display the output for the chosen `Nbits`.
void Do(int Nbits) const override;
......@@ -321,8 +312,6 @@ TestDisplaySumOfMultiply::TestDisplaySumOfMultiply(int resolution)
: TestDisplay(resolution)
{ }
TestDisplaySumOfMultiply::~TestDisplaySumOfMultiply() = default;
void TestDisplaySumOfMultiply::Do(int Nbits) const
{
......@@ -338,127 +327,123 @@ void TestDisplaySumOfMultiply::Display(int Nbits, double value1, int coefficient
PowerOfTwoApprox approximation2(Nbits, value2);
int approx = approximation1.Multiply(coefficient1) + approximation2.Multiply(coefficient2);
std::ostringstream oconv;
oconv << value1 << " * " << coefficient1 << " + " << value2 << " * " << coefficient2 << " = ";
PrintLine(Nbits, exact, static_cast<double>(approx), oconv.str(), "", RoundToInteger::yes);
}
std::ostringstream oconv;
oconv << value1 << " * " << coefficient1
<< " + " << value2 << " * " << coefficient2 << " = ";
//! Function for error handling. We will see later how to fulfill the same functionality more properly.
[[noreturn]] void Error(std::string explanation)
{
std::cout << "ERROR: " << explanation << std::endl;
exit(EXIT_FAILURE);
PrintLine(Nbits, exact, approx, oconv.str(), "", RoundToInteger::yes);
}
class TestDisplayContainer
{
public:
//! Constructor.
TestDisplayContainer(std::size_t capacity);
//! Destructor.
~TestDisplayContainer();
//! Add a new test_display_register.
//! At each call, the item to be registered is put at the first available position and internal current_position_
//! is incremented. If the end-user attempts to register more than three items, the error() function is called.
//! is incremented. If the end-user attempts to register more than three items, the Error() function is called.
void Register(TestDisplay* test_display);
//! Accessor to the i-th object in the container.
//! Returns the i-th element. If element is invalid, call `Error()`.
const TestDisplay& GetElement(std::size_t i) const;
//! Get the number of elements actually stored in the class (nullptr don't count).
//! Return the actual number of elements in the container.
std::size_t GetSize() const;
private:
//! Get the maximal number of elements that might be stored in the container.
//! Returns the maximum number of elements the container may carry.
std::size_t GetCapacity() const;
private:
//! Maximum number of items that might be registered in the container.
const std::size_t capacity_;
private:
//! List of all known `TestDisplay` objects.
TestDisplay** list_;
//! Index to place the next register object. If '3', no more object may be registered.
//! std::size_t is used as it is the convention within the STL for array indexes.
std::size_t current_position_ {};
//! Capacity.
const std::size_t capacity_;
};
TestDisplayContainer::TestDisplayContainer(std::size_t capacity)
: capacity_(capacity)
//! Function for error handling. We will see later how to fulfill the same functionality more properly.
[[noreturn]] void Error(std::string explanation)
{
std::cout << "ERROR: " << explanation << std::endl;
exit(EXIT_FAILURE);
}
TestDisplayContainer::TestDisplayContainer(std::size_t capacity)
: capacity_ { capacity }
{
list_ = new TestDisplay*[capacity];
for (auto i = 0ul; i < capacity; ++i)
list_[i] = nullptr;
for (auto index = 0ul; index < capacity; ++index)
list_[index] = nullptr;
}
TestDisplayContainer::~TestDisplayContainer()
{
for (auto i = 0ul; i < capacity_; ++i)
delete list_[i];
for (auto index = 0ul; index < capacity_; ++index)
delete list_[index];
delete[] list_; // don't forget the [] to delete an array!
}
void TestDisplayContainer::Register(TestDisplay* test_display)
{
if (current_position_ >= capacity_)
Error("TestDisplayContainer is already full; impossible to register a new element!");
list_[current_position_] = test_display;
++current_position_;
assert(current_position_ <= GetCapacity());
if (current_position_ == GetCapacity())
Error("There are already three elements stored in the contained; can't take more!");
list_[current_position_++] = test_display;
}
const TestDisplay& TestDisplayContainer::GetElement(std::size_t i) const
void Loop(int initial_Nbit, int final_Nbit, int increment_Nbit, const TestDisplayContainer& container)
{
if (i >= GetCapacity())
Error("You try to access an element out of bounds!");
if (list_[i] == nullptr) // equivalent to i >= GetSize()
Error("You try to access an element that was never initialized!");
return *list_[i];
}
const auto size = container.GetSize();
for (auto i = 0ul; i < size; ++i)
{
for (int nbits = initial_Nbit; nbits <= final_Nbit; nbits += increment_Nbit)
container.GetElement(i).Do(nbits);
std::cout << std::endl;
}
}
std::size_t TestDisplayContainer::GetCapacity() const
{
return capacity_;
}
std::size_t TestDisplayContainer::GetSize() const
{
return current_position_;
return current_position_;
}
//! For each container stored, loop oover all those bits and print the result on screen.
void Loop(int initial_Nbit, int final_Nbit, int increment_Nbit, const TestDisplayContainer& container)
const TestDisplay& TestDisplayContainer::GetElement(std::size_t i) const
{
for (auto i = 0ul; i < container.GetSize(); ++i)
{
decltype(auto) current_test_display = container.GetElement(i);
for (int nbits = initial_Nbit; nbits <= final_Nbit; nbits += increment_Nbit)
current_test_display.Do(nbits);
std::cout << std::endl;
}
if (i >= GetSize())
Error("You requested an element out of bounds!");
assert(list_[i] != nullptr); // should be true if first condition is right!
return *(list_[i]);
}
......@@ -471,7 +456,7 @@ int main(int argc, char** argv)
static_cast<void>(argc); // to silence warning about unused argc - don't bother
static_cast<void>(argv); // to silence warning about unused argv - don't bother
TestDisplayContainer container(3);
TestDisplayContainer container(3ul);
container.Register(new TestDisplayPowerOfTwoApprox065(1000000));
container.Register(new TestDisplayPowerOfTwoApprox035(1000000));
......@@ -481,4 +466,3 @@ int main(int argc, char** argv)
return EXIT_SUCCESS;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment