A while ago a tricky C++ interview question came across to me, and ever since I could not tell what I did wrong.
Create a base class named “Shape” with a method to return the area of the shape. Create a class named “Triangle” derived from the base class “Shape”.
Class “Triangle” must have two constructors. One receives the length of the (a) side of the triangle and the related (ma) height. The other receives the length of (a),(b),(c) sides of the triangle. In the second case, the constructor must validate the input by checking that the length of one side is smaller than the sum of the lengths of the other two sides. If the input is invalid, it should throw an exception. Implement the method (available in the base class) that calculates the area of the triangle on the basis of the available data.
You can use two formulas. If the length of a side and height is given:
T=(a*ma)/2
. If the lengths of the three sides are given, you can use the Heron formula:sqrt(s*(s-a)*(s-b)*(s-c))
wheres=(a+b+c)/2
This should be obvious for any candidate. It clearly asks if you know what the base principles of OOP is, and if you can solve a bit complex problem with it. Before I could just jump into it, I found something odd. The assessment requires you to create some class that behaves differently as they've created. It asks you to use some trickery to solve this problem.
Well, I, who read a bit about what SOLID is, and familiar with design patterns were trivial that using polymorphism is the way to solve this the most elegant way. My approach was something like this:
- Create the base class
- Create the derived class
- Use the derived class constructor as an abstract factory for a composite type, and make the implementation to act as a proxy toward the different implementations
- Create two other classes which handles the actual data and takes care of the calculation
- Take care of the exceptions using std::exception - these are tricky as well in C++
- Take care of the implementation
In the end my solution looked like this:
#include <exception>
#include <string>
#include <cmath>
class Shape
{
public:
virtual double Area() = 0;
};
class Exception : public std::exception
{
public:
Exception(std::string const &message) throw() : m_msg(message) {}
~Exception() throw() {}
virtual char const *what() const _NOEXCEPT { return m_msg.c_str(); }
private:
std::string m_msg;
};
class Triangle : public Shape
{
class TriangleSides;
class TriangleBase;
public:
Triangle(double base, double height);
Triangle(double a, double b, double c);
~Triangle();
double Area() override;
private:
Shape *m_shape;
class TriangleSides : public Shape
{
public:
TriangleSides(double a, double b, double c);
double Area() override;
private:
double m_a, m_b, m_c;
};
class TriangleBase : public Shape
{
public:
TriangleBase(double base, double height);
double Area() override;
private:
double m_base, m_height;
};
};
Triangle::Triangle(double base, double height) : m_shape(nullptr)
{
m_shape = new Triangle::TriangleBase(base, height);
}
Triangle::Triangle(double a, double b, double c) : m_shape(nullptr)
{
if (a + b <= c || a + c <= b || b + c <= a)
throw Exception("Any two sides of a triangle must be longer than one");
m_shape = new Triangle::TriangleSides(a, b, c);
}
Triangle::~Triangle()
{
delete m_shape;
}
double Triangle::Area()
{
if (m_shape)
return m_shape->Area();
else
return 0;
}
Triangle::TriangleSides::TriangleSides(double a, double b, double c) : m_a(a), m_b(b), m_c(c)
{
}
double Triangle::TriangleSides::Area()
{
const double s = (m_a + m_b + m_c) * .5;
return sqrt(s * (s - m_a) * (s - m_b) * (s - m_c));
}
Triangle::TriangleBase::TriangleBase(double base, double height) : m_base(base), m_height(height)
{
}
double Triangle::TriangleBase::Area()
{
return .5 * (m_base * m_height);
}