Exercises in this lecture   Go to the notes, in which this exercise belongs -- Keyboard shortcut: 'u'   Alphabetic index   Course home   

Exercise solution:
Conversion via constructors


Here are the revised program parts. First the header file:

// New example: Converting between Point an Tripple...

class Tripple;                 // NECESSARY FORWARD DECLARATION OF CLASS Tripple 

class Point {
private: 
  double x, y;

public:

  Point();                      // (0,7)
  Point(double d);              // constructor from double:  (d, 20)
  Point(double d, double e);    // (d, e)
  Point(Point& p);              // (p.x+1, p.y+2) 
  Point(Tripple t);             // (t.a, t.b)   NEW, INSTEAD OF CONVERSION IN Tripple.

  operator double() const;      // conversion operator to double: x+y

  double getx () const;
  double gety () const;
};

class Tripple {
private:
  int a, b, c;

public:
  friend class Point;           // GIVES POINT ACCESS TO PRIVATE a, b, and c.
                                // This is convenient in the new constructor Point::Point(Tripple) 
  Tripple();                    // (0, 0, 0)
  Tripple(int x, int y, int z); // (x, y, z)
  Tripple(Point p);             // (p.x, p.y, 0)

  friend std::ostream& operator<<(std::ostream&, const Tripple&);
};


std::ostream& operator<<(std::ostream&, const Point&);
std::ostream& operator<<(std::ostream&, const Tripple&);

The cpp file:

#include <cmath>
#include <iostream>
#include "point1.h"

// Tripple:

Tripple::Tripple(): a(0), b(0), c(0){
}

Tripple::Tripple(int x, int y, int z): a(x), b(y), c(z){
}

Tripple::Tripple(Point p): a(int(p.getx())), b(int(p.gety())), c(0){
}

std::ostream& operator<<(std::ostream& s, const Tripple& tr){
  return s << "[" << tr.a << "," << tr.b << "," << tr.c << "]";
}



// Point:

Point::Point(): x(0.0), y(7.0){
}

Point::Point(double x_coord): x(x_coord), y(20.0){
}

Point::Point(double x_coord, double y_coord): x(x_coord), y(y_coord){
}

Point::Point(Point& p): x(p.x + 1.0), y(p.y + 2.0){
}

Point::Point(Tripple t): x(t.a), y (t.b){     // NEW CONSTRUCTOR
}                                             // Can access a and b in t because Point 
                                              // has granted friendship to Tripple.

double Point::getx () const{
  return x;
}

double Point::gety () const{
  return y;
}

Point::operator double() const {
  return x + y;
}

std::ostream& operator<<(std::ostream& s, const Point& p){
  return s << "(" << p.getx() << "," << p.gety() << ")" ;
}


The client program:

#include <iostream>
#include <string>
#include "point1.h"

using namespace std;

int main(){
  Point p1, p2;      // Both (0, 7)
  Tripple t1;        // (0, 0, 0)

  cout << "t1: " << t1 << endl;  // [0,0,0]

  t1 = p2;           // p2 is copied into the tripple constructor as (1,9). The tripple constructor makes (1,9,0).

  p1 = t1;           // (1,9,0) is default copied into the constructor Point(Tripple), as (1,9,0), which makes the point (1,9).

  cout << "t1: " << t1 << endl;   // [1,9,0]
  cout << "p1: " << p1 << endl;   // (1,9)
}

When I run this program I get this output:

t1: [0,0,0]
t1: [1,9,0]
p1: (1,9)

As it appears, we get natural and expected results. Thus, it turns out to be easier to control the conversions in this variation of the program

When we, finally, change the Point and Tripple constructors, we avoid the unfortunate activation of the Point constructor during the conversion. We get natural results.