#include "Avatar.h"
#include <iostream>
int main()
{
try
{
Avatar avatar1("Avatar 1", 10, 15, 17);
//avatar1.setStrength(0); // Out of bounds
//avatar1.setSpeed(101); // Out of bounds
//avatar1.agility = Checked<int>(16, 15, 17); // Cannot use deleted function
avatar1.display();
Avatar avatar2("Avatar 2", 5, -3, 8); // Out of bounds in constructor
avatar2.display();
}
catch (OutOfBoundsException<int> & outOfBoundsException)
{
std::cerr << "Exception caught: " << outOfBoundsException.what() << std::endl;
}
return 0;
}
#pragma once
#include "Checked.h"
class Avatar
{
private:
const std::string _name;
static std::string visualiseAttribute(int value, int min, int max);
public:
Checked<int> strength;
Checked<int> speed;
Checked<int> agility;
Avatar(std::string name, int strength, int speed, int agility);
void display();
};
#include "Avatar.h"
#include <iostream>
#include <sstream>
Avatar::Avatar(std::string name, int strength, int speed, int agility) :
_name(std::move(name)),
strength(strength, 1, 100),
speed(speed, 1, 100),
agility(agility, 1, 100)
{
}
void Avatar::display()
{
std::cout << "Avatar: " << _name << std::endl;
std::cout << "\tStrength: " << strength << ' ' << visualiseAttribute(strength, 1, 100) << std::endl;
std::cout << "\tSpeed: " << speed << ' ' << visualiseAttribute(speed, 1, 100) << std::endl;
std::cout << "\tAgility: " << agility << ' ' << visualiseAttribute(agility, 1, 100) << std::endl;
}
std::string Avatar::visualiseAttribute(int value, int min, int max)
{
std::stringstream ss;
for (int i = min; i <= max; i++)
ss << (i <= value ? '+' : ' ');
return ss.str();
}
#pragma once
#include "OutOfBoundsException.hpp"
#include "ValueTooLargeException.hpp"
#include "ValueNotSetException.hpp"
template<typename T> class Checked
{
private:
const T _min;
const T _max;
T _actual;
bool _isValid;
public:
Checked(T actual, T min, T max) :
_min(min),
_max(max)
{
if (min > max)
throw ValueTooLargeException(min, max, "min cannot be larger than max.");
set(actual);
}
Checked & operator=(const Checked & other) = delete; // Do not allow assignment
Checked & operator=(Checked && other) = delete; // Do not allow move assignment
bool isValid() const { return _isValid; }
T getMin() const { return _min; }
T getMax() const { return _max; }
T get() const { return _isValid ? _actual : throw ValueNotSetException("no valid value have been provided."); }
void set(T value)
{
if (_min <= value && value <= _max)
{
_actual = value;
_isValid = true;
}
else
{
throw OutOfBoundsException(value, _min, _max, "trying to set an invalid value.");
_isValid = false;
}
}
Checked & operator=(T value)
{
set(value);
return *this;
}
operator T() const { return get(); }
};
#pragma once
#include <stdexcept>
#include <sstream>
template<typename T> class OutOfBoundsException : public std::out_of_range
{
private:
static std::string createMessage(T actual, T min, T max, const std::string & message = "")
{
std::stringstream ss;
ss << actual << " is out of bounds [" << min << ", " << max << "]: " << message;
return ss.str();
}
public:
OutOfBoundsException(T actual, T min, T max, const std::string & message = "") :
std::out_of_range(createMessage(actual, min, max, message))
{
}
};
#pragma once
#include <stdexcept>
#include <sstream>
template<typename T> class ValueTooLargeException : public std::out_of_range
{
private:
static std::string createMessage(T actual, T max, const std::string & message = "")
{
std::stringstream ss;
ss << actual << " cannot exceed " << max << "]: " << message;
return ss.str();
}
public:
ValueTooLargeException(T actual, T max, const std::string & message = "") :
std::out_of_range(createMessage(actual, max, message))
{
}
};
#pragma once
#include <stdexcept>
#include <sstream>
class ValueNotSetException : public std::runtime_error
{
public:
ValueNotSetException(const std::string & message = "") :
std::runtime_error(message)
{
}
};