0

I am 1st semester computer science student having trouble on this problem.

Write a class called Rectangle with double fields for its length and width, set methods for both fields, a constructor that takes two double parameters and passes them to the set methods. It should include a method called area and perimeter area of the Rectangle and the perimeter of the Rectangle.

Write a class called Square that inherits from Rectangle. It should have a constructor that takes one double parameter and passes it to the base class constructor for both parameters (the body of the constructor will be empty). Square will also need to override the setLength() and setWidth() functions of its base class such that if either of its dimensions is set to a new value, then both of its dimensions will be set to that new value (so that it remains a square). Hint: you can have the overridden versions call the versions in the base class.

I am using Code::Blocks and C++ as the language.

Rectangle.hpp

#include <iostream>
using namespace std;
#include <cmath>
#ifndef Rectangle_HPP
#define Rectangle_HPP

class Rectangle
{
 protected:
 double length;
 double width;
 public:

 Rectangle();
 Rectangle(double,double);
 double area();
 double perimeter();
 void setLength(double);
 void setWidth(double);
};

#endif

Rectangle.cpp

#include <iostream>
using namespace std;
#include <cmath>
#include "Rectangle.hpp"

Rectangle::Rectangle(double l, double w)
 {
   length = l;
   width  = w;
 }

double Rectangle::area()
 {
  return (width * length);
 }

double Rectangle::perimeter()
 {
    return (2*(width + length));
 }

void Rectangle::setLength(double l)
{
  length = l;
}

void Rectangle::setWidth(double w)
{
  width = w;
}

Square.hpp

#include <iostream>
using namespace std;
#include <cmath>
#include "Rectangle.hpp"
#ifndef Square_HPP
#define Square_HPP

class Square: public Rectangle
{
  public:

  Square();
  Square(double);
  void setLength(double);
  void setWidth(double);
};
#endif

Square.cpp

#include <iostream>
using namespace std;
#include <cmath>
#include "Rectangle.hpp"
#include "Square.hpp"

Square::Square(double side){}

void Square::setLength(double side)
{
  length = side;
  width = side;
}

void Square::setWidth(double side)
{
  length = side;
  width = side;
}

 int main()
{
    return 1;
}

I have tested the Rectangle.hpp and the Rectangle.cpp by themselves with a main method, and they seem to work fine, but I am having trouble with the Square.hpp and Square.cpp. Is there anything that you see that I am obviously missing. The undefined reference to Rectangle::Rectangle is the only error that Code::Blocks is returning to me so far. It says the error is in the Square.cpp file. I have made sure that all four files are part of the same project, so that shouldn't be the issue.

Sayse
  • 42,633
  • 14
  • 77
  • 146
Riddler
  • 11
  • 3
  • 1
    TLDR; That is a bad assignment: Although, mathematically a square is a rectangle, in terms of programming it is not (saying a square `is a` rectangle is wrong) - note a square needs only one dimension, a rectangle, two. –  Feb 17 '16 at 21:41
  • In case your class doesn't go into [LSP](http://stackoverflow.com/questions/56860/what-is-the-liskov-substitution-principle) with this example, imagine you're writing a function that accepts any `Rectangle` and calls `setWidth` on it. This function would likely expect the length to remain constant. However, if a `Square` object is passed in, the length changes! This is not something you want to happen in real code. The trick is finding a good balance of what the base class or interface guarantees with enough leeway for different implementations to do usefully different things. – chris Feb 17 '16 at 21:46
  • @DieterLücking That was my initial reaction too. If neither defined setWidth or setLength (i.e. they become immutable) then it might then be valid inheritance. – Steve Kidd Feb 17 '16 at 21:46
  • Possible duplicate of [Class inherited from class without default constructor](http://stackoverflow.com/questions/3714162/class-inherited-from-class-without-default-constructor) – Weak to Enuma Elish Feb 17 '16 at 21:47
  • @JamesRoot I didn't know that an inherited or even a derived class needed a default constructor! – Steve Kidd Feb 17 '16 at 21:48
  • Don't have time to type up an answer. Square::Square should pass the input parameter to base class constructor as both parameters. – Steve Kidd Feb 17 '16 at 21:50
  • Thanks everyone for the input, I eventually got it. – Riddler Feb 18 '16 at 00:33

2 Answers2

0

"The undefined reference to Rectangle::Rectangle is the only error "

You really should take what the linker tells you seriously.

In rectangle.h you have defined a default constructor

Rectangle();

But nowhere have you implemented it! So the linker complains.

Write something like this:

Rectangle::Rectangle()
: length( 0 )
, width( 0 )
{}
ravenspoint
  • 19,093
  • 6
  • 57
  • 103
  • Sorry but I don't agree with this. A zero length and width 'rectangle' is not really a rectangle. It might be a point. The problem is that all the parameter-less constructors need removing and the Square::Square(double length) constructor needs to explicity call the Rectangle::Rectangle(double l, double w) constructor. – Steve Kidd Feb 18 '16 at 12:02
  • My 'fix' will fix the linker error that the OP reported. ( It is a philosophical question whether a rectangle of zero-sides is a point or an extremely small rectangle. The linker doesn't care. ) – ravenspoint Feb 18 '16 at 12:58
  • I accept that a zero size rectangle is a philosophical question. I might have made a better argument if I questioned why any default value is appropriate. Also, is a default of 0, 0 better than 1,1 or any other value? Even so, i accept there will be situations where a default is appropriate. I would like to think that providing a default would be less common than requiring explicit dimensions. You are, of course, right to say your answer removes the linker error although it is not the only way of fixing it. – Steve Kidd Feb 19 '16 at 15:31
  • There are always many ways to fix build errors. I like to do minimum violence to existing code, to minimize the chance of breaking something else. In particular: avoid changing an exiting class interface. – ravenspoint Feb 19 '16 at 15:45
  • And I agree. However this was new code written by the OP, wasn't it? – Steve Kidd Feb 19 '16 at 16:15
0

The Rectangle::Rectangle() parameter-less constructor should not be declared (in my interpretation of the spec).

Square::Square() with no parameters should not have been defined (in my interpretation of the spec).

The Square::Square(double) constructor should not call the base class's default constructor (which your code currently does). Instead the requirements ask for

Square::Square(double length) : Rectangle(length, length) {}

Hope that helps.

Steve Kidd
  • 356
  • 3
  • 10