Department of Engineering

IT Services

C++ and Building Classes (a range-limited integer example)

We're going to create a type of variable that will only store integers in a certain range. We'll build the class up gradually, first dealing with the value of the variable, then making the variable behave more like a normal integer. It's assumed that you've seen C++ classes before. Not all the code details will be explained, but with luck you should be able to adapt the code for your own purposes.

This code is developed from code in "C++ Timesaving Techniques For Dummies" by Matthew Telles which is online at http://www.dummies.com/go/cplusplus/tstfd

Initialising and Protecting

The class needs to store the variable's value, and needs to store the maximum and minimum values. If we make these values public like this

class  IntRange {
public:
  int iMin;
  int iMax;
  int iValue;
}

programmers can then create a variable (by doing IntRange ir;, say) then set ir.iValue to whatever they want. We have to control access to iValue by making it private. We might as well make the other fields private too. Once we've done that we can provide functions that set these fields, checking that the values are appropriate.

// Developed from http://www.dummies.com/go/cplusplus/tstfd
// C++ Timesaving Techniques For Dummies by Matthew Telles
#include <limits> // for min/max integer 
using namespace std;

class  IntRange {
private:
  int iMin;
  int iMax;
  int iValue;

public:
  IntRange() {
    iMin=numeric_limits<int>::min();
    iMax=numeric_limits<int>::max();
    iValue=iMin;
  }

  IntRange(int min, int max) {
    if(min <=max) {
      iMin=min;
      iMax=max;
    }
    else {
      iMin=max;
      iMax=min;
    }
    iValue=iMin;

  }

  IntRange(int min, int max, int value) {
    if(min <=max) {
      iMin=min;
      iMax=max;
    }
    else {
      iMin=max;
      iMax=min;
    }

    if (value < iMin)
      value = iMin;
    else if   (value > iMax)
      value = iMax;
    iValue=value;
  }
};

This code creates 3 constructors that can be called this way

IntRange ir;
IntRange ir(0, 20);
IntRange ir(-10, 10, 5);

But there's another way that an IntRange variable that might be created which will bypass these constructors. If a programmer writes

IntRange ir;
IntRange ir2=ir;

the compiler will try to create ir2 using a copy constructor. Here's the copy constructor we need.

    IntRange(const IntRange& aCopy) {
    iMin=aCopy.iMin;
    iMax=aCopy.iMax;
    iValue=aCopy.iValue;
  }

Providing Read Access

We've ensured that the variable is initialised with appropriate values, but those values are private. 3 little public functions give read access to the values

  int GetMin() {
    return iMin;
  }

  int GetMax() {
    return iMax;
  }

  int GetValue() {
    return iValue;
  }

Providing Write Access

Now we'll let the user change the value in a controlled way. We want to let users do

IntRange ir;
ir=7;

This can be done by redefining what the "=" sign means in this situation. The code we need is

  IntRange& operator=(int value)
  {
    if (value < iMin)
      value = iMin;
    else if   (value > iMax)
      value = iMax;
    iValue=value;
    return *this;
  }

There are 2 things to note

  • The code that checks the value duplicates code we have used before, so we'll put the code into a function called SetValue
  • this is a pointer to the current variable. *this is returned so that chaining expressions like IntRange ir; ir=ir=3; work

In a similar way we can create code so that floats can be used to set values

IntRange ir;
ir=7.5;

The code is

  IntRange& operator=(double value)
  {
    SetValue ( static_cast<int>(value));
    return *this;
  }

More like an integer

By redefining a few operators for comparing and printing we can make the new type easier to use. With the following functions

  bool operator<(const IntRange& aRange, int aValue) {
    return aRange.GetValue() < aValue;
  }

  bool operator==(const IntRange& aRange, int aValue) {
    return aRange.GetValue() == aValue;
  }

  ostream &operator <<(ostream &stream, IntRange ir) {
    cout << ir.GetValue();
    return stream;
  };

the following code should work

IntRange ir;
if (ir < 6 or ir == 8)
   cout << ir;

The Full Code

Here's the full code plus a main routine to try it out

// from http://www.dummies.com/go/cplusplus/tstfd
// C++ Timesaving Techniques For Dummies by Matthew Telles
#include <iostream>
#include <limits>
using namespace std;

class  IntRange {
private:
  int iMin;
  int iMax;
  int iValue;

  void SetValue (int value) {
   if (value < iMin)
      value = iMin;
    else if   (value > iMax)
      value = iMax;
    iValue=value;
  }

public:
  IntRange() {
    iMin=numeric_limits<int>::min();
    iMax=numeric_limits<int>::max();
    iValue=iMin;
  }

  IntRange(int min, int max) {
    if(min <=max) {
      iMin=min;
      iMax=max;
    }
    else {
      iMin=max;
      iMax=min;
    }
    iValue=iMin;
  }

  IntRange(int min, int max, int value) {
    if(min <=max) {
      iMin=min;
      iMax=max;
    }
    else {
      iMin=max;
      iMax=min;
    }
    SetValue(value);
  }

  IntRange(const IntRange& aCopy) {
    iMin=aCopy.iMin;
    iMax=aCopy.iMax;
    iValue=aCopy.iValue;
  }

  int GetMin() {
    return iMin;
  }

  int GetMax() {
    return iMax;
  }

  IntRange& operator=(int value)
  {
    SetValue(value);
    return *this;
  }

  IntRange& operator=(double value)
  {
    SetValue (static_cast<int>(value));
    return *this;
  }

  int GetValue() const {
    return iValue;
  }
};

  bool operator<(const IntRange& aRange, int aValue) {
    return aRange.GetValue() < aValue;
  }

  bool operator==(const IntRange& aRange, int aValue) {
    return aRange.GetValue() == aValue;
  }

ostream &operator <<(ostream &stream, IntRange ir) {
  cout << ir.GetValue();
  return stream;
}

int main() {
    IntRange foo(0,20);

    foo=1;
    foo=9;
    cout << foo << endl;

    if(foo < 10)
      cout << "foo is less than 10" << endl;
    foo=21;
    cout << foo << endl;

  }

Note that

  • Currently the code silently sets the variable to the minimum or maximum allowed when given out-of-range values. Maybe it should print an error message or throw an exception.
  • Only a few of the many operators are dealt with.