Area calculator for shapes as an OOP interview test 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))
  where s=(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 &lt;exception&gt;
#include &lt;string&gt;
#include &lt;cmath&gt;

class Shape
{
public:
    virtual double Area() = 0;
};

class Exception : public std::exception
{
public:
    Exception(std::string const &amp;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 &lt;= c || a + c &lt;= b || b + c &lt;= 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-&gt;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);
}
I see some things that may help you improve your code.

Don't overcomplicate your code

The only thing required of the Shape and Triangle classes is the calculation of area.  For that reason, the code can be considerably simplified if the constructor calculates and stores the area.

Use const where practical

The Area() function probably shouldn't alter the underlying Shape object, so it makes sense to declare it const.

Use a standard exception where appropriate

There's really nothing, well... exceptional about the Exception class, so it seems not really to be required.  Maybe std::domain_error could be used instead like this:

throw std::domain_error("Any two sides of a triangle must be longer than one");


Provide a test driver

This is more about getting a good review rather than the code itself, but it's often good to give reviewers a complete, compileable example to allow them to see the code in context.  Here's what I used:

#include &lt;iostream&gt;
int main() {
    Triangle t1{3, 4, 5};
    std::cout &lt;&lt; t1.Area() &lt;&lt; '\n';
    try {
        Triangle t2{3, 4, 15};
    }
    catch (std::exception &amp;e) {
        std::cout &lt;&lt; e.what() &lt;&lt; '\n';
    }
    Triangle t3{3, 4};
    std::cout &lt;&lt; t3.Area() &lt;&lt; '\n';
}


Use std:: for math functions

The sqrt function is often in the global namespace, but it's required to be in the std namespace.  For that reason, it's probably safer to write std::sqrt than just sqrt.

Use standard keywords

Instead of _NOEXCEPT which is not standard, the code could use noexcept.

Reworked example

#include &lt;string&gt;
#include &lt;cmath&gt;
#include &lt;stdexcept&gt;

class Shape
{
public:
    virtual double Area() const = 0;
};

class Triangle : public Shape
{
public:
    Triangle(double base, double height);
    Triangle(double a, double b, double c);
    double Area() const override { return area;}

private:
    double area;
};

Triangle::Triangle(double base, double height) 
    : area{(base * height)/2}
{
}

Triangle::Triangle(double a, double b, double c) 
    : area{(a-b-c)*(-a+b-c)*(a+b-c)*(a+b+c)/16}
{
    if (area &lt; 0)
        throw std::domain_error("Any two sides of a triangle must be longer than one");
    area = std::sqrt(area);
}