Point.h
#ifndef POINT_H_
#define POINT_H_
// Class that represents a two-dimesional integral coordinate plane
class Point {
public:
Point(int x, int y); // constructor
int get_x() const { return x_; } // inline member function
int get_y() const { return y_; } // inline member function
double Distance(const Point &p) const; // member function
void SetLocation(int x, int y); // member function
private:
int x_; // data member
int y_; // data member
}; // class Point
#endif // POINT_H_
Point.cc
#include "Point.h"
#include <cmath> // sqrt
Point::Point(const int x, const int y) {
// BAD STYLE: shouldn't mix-and-match direct field access (x_)
// and access via this (this->y_).
x_ = x;
this->y_ = y; // this-> is optional, unless names conflict
}
double Point::Distance(const Point& p) const {
// We can access p's x_ and y_ variables either through the
// get_x(), get_y() accessor functions, or the x_, y_ private
// member variables directly, since we're in a member function of
// the same class (BAD STYLE to mix-and-match, though).
double distance = (x_ - p.get_x()) * (x_ - p.get_x());
distance += (y_ - p.y_) * (y_ - p.y_);
return sqrt(distance);
}
void Point::SetLocation(const int x, const int y) {
x_ = x;
y_ = y;
}
Point_2011.h
#ifndef POINT_2011_H_
#define POINT_2011_H_
class Point {
public:
Point(int x, int y); // constructor
// disable copy constructor and assignment operator by specifying
// them as deleted functions (new in C++ 2011)
Point(const Point& copyme) = delete;
Point& operator=(const Point& rhs) = delete;
int get_x() const { return x_; } // inline member function
int get_y() const { return y_; } // inline member function
void Clone(const Point& copy_from_me); // update self
double Distance(const Point& p) const;
void SetLocation(int x, int y);
private:
int x_; // data member
int y_; // data member
}; // class Point
#endif // POINT_2011_H_
Point_2011.cc
#include "Point_2011.h"
#include <cmath>
#include <iostream>
Point::Point(const int x, const int y) : x_(x), y_(y) {
std::cout << "Calling Point constructor" << std::endl;
}
void Point::Clone(const Point& copy_from_me) {
x_ = copy_from_me.x_;
y_ = copy_from_me.y_;
}
double Point::Distance(const Point& p) const {
double distance = (x_ - p.x_) * (x_ - p.x_);
distance += (y_ - p.y_) * (y_ - p.y_);
return sqrt(distance);
}
void Point::SetLocation(const int x, const int y) {
x_ = x;
y_ = y;
}
sanepoint_2011.cc
#include <cstdlib>
#include "Point_2011.h"
int main(int argc, char **argv) {
Point x(1, 2);
Point y(3, 4);
x.Clone(y);
// Point z(x); // compiler error, copy constructor is disabled.
// x = y; // compiler error, assignment operator is disabled.
return EXIT_SUCCESS;
}
Complex.h
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include <iostream>
namespace complex {
class Complex {
// Style tip: always put your public members before private members.
public:
Complex(double real, double imag); // Constructor
Complex(double real); // overloaded Constructor
Complex(const Complex& copyme); // Copy constructor
~Complex(); // Destructor
// Accessors / mutators, defined inline.
double real() const { return real_; }
double imag() const { return imag_; }
void set_real(const double real) { real_ = real; }
void set_imag(const double imag) { imag_ = imag; }
// Override the "-", "=", "+=", and "-=" operators.
// Note that "-", like "+", could have been a non-member
// function. That would generally be better style since it can reduce
// the amount of code with access to private instance data, and allows
// "-" to treat its operators symmetrically, but we made it a member
// function here as an example of what is possible.
// "=", "+=", and "-=" normally should be member functions since
// they do mutate the object's state instead of producing a new
// object as a result.
Complex operator-(const Complex& a) const;
Complex& operator=(const Complex& a);
Complex& operator+=(const Complex& a);
Complex& operator-=(const Complex& a);
// Overload ">>" for istream. Note that this is a global
// function, not a member function of class Complex. It could
// have been implemented as an ordinary, non-friend function
// using the set_real() and set_imag() member functions and that
// would generally be better style since it reduces the code that
// has access to private data. See "<<" for an example of a
// non-friend stream i/o function.
friend std::istream& operator>>(std::istream& in, Complex& a);
private:
double real_, imag_; // Member variables.
}; // class Complex
// additional overloaded operators (not member or friend functions)
// (see above notes above about "-" and "<<", which should usually
// be done this way also when possible)
Complex operator+(const Complex& a, const Complex& b);
std::ostream& operator<<(std::ostream& out, const Complex& a);
} // namespace complex
#endif // COMPLEX_H_
Complex.cc
#include "Complex.h"
#include <iostream>
#include <sstream>
#include <string>
// This sample implementation prints diagnostic messages that
// would not be included in a production class, but are helpful
// for observing how the class works.
namespace complex {
Complex::Complex(const double real, const double imag) {
std::cout << "constructor(" << real << "," << imag << ")";
std::cout << ", the constructed object is at " << this << std::endl;
this->real_ = real;
this->imag_ = imag;
}
Complex::Complex(const double real) {
std::cout << "constructor(" << real << ")";
std::cout << ", the constructed object is at " << this << std::endl;
this->real_ = real;
this->imag_ = 0.0;
}
Complex::Complex(const Complex& copyme) {
std::cout << "copy constructor(copy " << ©me << ")";
std::cout << ", the constructed object is at " << this << std::endl;
this->real_ = copyme.real_;
this->imag_ = copyme.imag_;
}
Complex::~Complex() {
std::cout << "destructor of object at " << this << std::endl;
}
Complex Complex::operator-(const Complex& a) const {
Complex tmp(0, 0);
std::cout << "-: subtracting " << this << " - " << &a;
std::cout << ", tmp is at " << &tmp << std::endl;
tmp.real_ = this->real_ - a.real_;
tmp.imag_ = this->imag_ - a.imag_;
return tmp;
}
Complex& Complex::operator=(const Complex& a) {
std::cout << "=operator: " << this << " = " << &a << std::endl;
if (this != &a) {
this->real_ = a.real_;
this->imag_ = a.imag_;
}
return *this;
}
Complex& Complex::operator+=(const Complex& a) {
std::cout << "+=operator: " << this << " += " << &a << std::endl;
this->real_ += a.real_;
this->imag_ += a.imag_;
return *this;
}
Complex& Complex::operator-=(const Complex& a) {
std::cout << "-=operator: " << this << " -= " << &a << std::endl;
this->real_ -= a.real_;
this->imag_ -= a.imag_;
return *this;
}
// additional non-member overloaded operators in complex namespace
Complex operator+(const Complex& a, const Complex& b) {
Complex tmp = a;
std::cout << "+: adding " << &a << " + " << &b;
std::cout << ", tmp is at " << &tmp << std::endl;
tmp += b;
return tmp;
}
std::ostream& operator<<(std::ostream& out, const Complex& a) {
std::cout << "<<operator: from " << &a << std::endl;
out << "(" << a.real() << " + " << a.imag() << "i)";
return out;
}
std::istream& operator>>(std::istream& in, Complex& a) {
std::cout << ">>operator: to " << &a << std::endl;
double realtmp, imagtmp;
// Make sure the next character is '('.
if (in.peek() != '(') {
in.setstate(std::ios_base::failbit);
return in;
}
in.get();
// Try to read the next thing as a double.
if (!(in >> realtmp)) {
return in;
}
// Read the next three chars (' + ').
if (in.get() != ' ')
return in;
if (in.get() != '+')
return in;
if (in.get() != ' ')
return in;
// Try to read the next token as a double ending in 'i'.
std::string x;
if (!getline(in, x, 'i')) {
return in;
}
std::stringstream ss(x);
if (!(ss >> imagtmp)) {
return in;
}
// Verify the next char is ')'.
if (in.peek() != ')') {
in.setstate(std::ios_base::failbit);
return in;
}
in.get();
a.real_ = realtmp;
a.imag_ = imagtmp;
return in;
}
} // namespace complex
testcomplex.cc
#include <iostream>
#include <sstream>
#include "Complex.h"
int main(int argc, char** argv) {
// Invokes the constructors for a,b.
complex::Complex a(1, 1), b(2, 2);
complex::Complex c = b; // Invokes the copy constructor for c.
// Invokes the "+" operator; our implementation of the "+" operator
// allocates a "temp" variable, so a constructor for it is invoked.
// g++ has various optimizations including "return by value" that
// can eliminate some of the potential copying implied by the code.
// since we're assigning the return value from "+" to the variable
// "d", instead of allocating "temp" in the stack frame of "+",
// it could use the space allocated for "d" to hold temp's
// contents, avoiding an extra copy constructor / allocation.
// that's not guaranteed behavior and it might change from one
// release of the compiler to another, but g++ will try to
// reduce copying when it's safe.
complex::Complex d = a + b;
std::cout << "[address of d:] " << &d << std::endl;
a = d; // Invokes the "=" operator on a with argument d.
b += a; // Invokes the "+=" operator on b with argument a.
c = 1 + c; // invokes the symmetric "+" operator on Complex(1) and c
// (implicit conversion from 1 using Complex(real) ctr)
// Invokes the "<<" operator with args (cout, c), then (cout, endl).
std::cout << c << std::endl;
std::stringstream str("(10 + 11i)");
// Invokes the ">>" operator with args (str, d).
str >> d;
// Invokes the "<<" operator with args (cout, d), then (cout, endl).
std::cout << d << std::endl;
return EXIT_SUCCESS;
}
heappoint.cc
#include <iostream>
#include "Point.h"
using std::cout;
using std::endl;
int* AllocateInt(int x) {
int* heapy_int = new int;
*heapy_int = x;
// could also have been: int *heapy_int = new int(x);
return heapy_int;
}
Point* AllocatePoint(int x, int y) {
Point* heapy_point = new Point(x, y);
return heapy_point;
}
int main(int argc, char** argv) {
Point* x = AllocatePoint(1, 2);
int* y = AllocateInt(3);
cout << "x's x_ coordinate: " << x->get_x() << endl;
cout << "distance between x and self: " << x->Distance(*x) << endl;
cout << "y: " << y << ", *y: " << *y << endl;
delete x;
delete y;
return EXIT_SUCCESS;
}
arrays.cc
#include <iostream>
#include "Point.h"
int main(int argc, char** argv) {
int stack_int; // stack-allocated int
int* heap_int = new int; // heap-allocated, uninitialized int
int* heap_int_init = new int{12}; // heap-allocated, initialized to 12
int stack_arr[3]; // stack-allocated array of 3 uninitialized ints
int* heap_arr = new int[3]; // heap-allocated array of 3 uninitialized ints
// Value initialize array elements (to zeros).
int* heap_arr_init_val = new int[3](); // heap-alloc array of 3 zeros
// C++11: can use a braced list of element initializers.
// if initializer list is short, remaining elements are value initialized.
int* heap_arr_init_lst = new int[3]{4, 5}; // heap-alloc array of {4, 5, 0}
Point stack_pt(1, 2); // stack-allocated Point object.
Point* heap_pt = new Point(1, 2); // heap allocated Point object.
// would be OK if we had a default constructor for Points, but
// since we don't, the compiler complains.
// Point *heap_pt_arr_err = new Point[2]; // heap-alloc, value initialized
// C++11: can use a braced list of element initializers.
Point* heap_pt_arr_init_lst = new Point[2]{1, 2}, {3, 4}; // missing an outer {} due to markdown error
delete heap_int; // correct
delete heap_int_init; // correct
delete heap_pt; // correct
delete heap_arr; // incorrect! should be delete[] heap_arr
delete[] heap_arr_init_val; // correct
delete[] heap_pt_arr_init_lst; // correct
// memory leak of heap_arr_init_lst!
return EXIT_SUCCESS;
}
Str.h
// Specification of a simple string class.
// A Str object wraps an ordinary C-string to make a C++ object with
// some basic operations. Each str owns a dynamically allocated char
// array that holds the underlying \0-terminated C string.
#ifndef STR_H_
#define STR_H_
#include <iostream> // for stream output
class Str {
public:
// constructors
// create empty string
Str();
// create Str from c-string s
Str(const char* s);
// copy constructor - initialize this to be a copy of s
Str(const Str& s);
// destructor
~Str();
// return length of this string
int length() const;
// return a new c-string allocated on the heap with
// a copy of this Str's string data
char* c_str() const;
// append contents of s to the end of this string
void append(const Str& s);
// string assignment: replace this string with a copy of s
Str& operator=(const Str& s);
// stream output (global function, not class member)
friend std::ostream& operator<<(std::ostream& out, const Str& s);
private:
// Str representation
char* st_; // c-string on heap with data bytes terminated by \0
}; // class Str
#endif // STR_H_
Str.cc
// Implementation of a simple string class.
#include "Str.h"
#include <cstring>
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;
// Print trace messages with object addresses to show when functions get called.
#define TRACE(what) cout << "- Str::" what << " called on " << this << endl
// constructors
Str::Str() {
TRACE("default constructor");
// allocate empty string
st_ = new char[1];
st_[0] = '\0';
}
Str::Str(const char* s) {
TRACE("c-string constructor");
int len = strlen(s);
st_ = new char[len + 1];
strncpy(st_, s, len + 1);
}
Str::Str(const Str& s) {
TRACE("copy constructor");
int len = strlen(s.st_);
st_ = new char[len + 1];
strncpy(st_, s.st_, len + 1);
}
// destructor
Str::~Str() {
TRACE("destructor");
delete [] st_;
}
// operations
int Str::length() const {
TRACE("length");
return strlen(st_);
}
char* Str::c_str() const {
TRACE("c_str");
int len = strlen(st_);
char* result = new char[len + 1];
strncpy(result, st_, len + 1);
return result;
}
void Str::append(const Str& s) {
TRACE("append");
int len1 = strlen(st_);
int len2 = strlen(s.st_);
char* newst = new char[len1 + len2 + 1];
strncpy(newst, st_, len1 + 1);
strncat(newst, s.st_, len2);
delete [] st_;
st_ = newst;
}
Str& Str::operator=(const Str& s) {
TRACE("assignment");
// do nothing if trying to assign a string to itself
if (this == &s) {
return *this;
}
// Replace string array with one of correct size
// (Note: this is where the self-assignment test _really_ matters)
// (Note: a better implementation would re-use the existing array
// if it's long enough, but not too long)
delete [] st_;
int len = strlen(s.st_);
st_ = new char[len + 1];
// copy characters and return
strncpy(st_, s.st_, len + 1);
return *this;
}
// stream output
// (Note: not a member function of Str. This is an overloaded global
// function that is a friend of Str so it can access private data)
ostream& operator<<(ostream& out, const Str& s) {
out << s.st_;
return out;
}
strtest.cc
// CSE 333 Lecture 12 demo: strtest.cc
// Hal Perkins
// Test program for a simple string class.
// Demonstrates string class with constructors, destructors,
// and assignment. Trace output from Str.cc will show when
// the various constructors and destructor are called.
#include <iostream>
#include "Str.h"
using std::cout;
using std::endl;
// print message to show progress
void here(int n) {
cout << "main: " << n << endl;
}
// id(x) == x (tests copy construtor)
Str id(Str s) {
cout << "id: reached start of code" << endl;
return s;
}
// create some strings and play with them
int main() {
// local variables in main's stack frame
// (destructors called when main exits)
Str s1, s2; // default constructors
Str hello("hello"); // c-string constructor
Str howdy = hello; // copy constructor
here(1);
// get c-string from Str
char* hi = howdy.c_str();
cout << hi << endl;
delete [] hi;
here(2);
// test append (constructs a Str argument and discards it)
hello.append(" there");
cout << hello << endl;
cout << " length is " << hello.length() << endl;
here(3);
// assignment operator and Str(char *) constructor
s1 = "howdy";
cout << s1 << endl;
here(4);
// copy constructors
s2 = id(hello);
cout << s2 << endl;
here(5);
// heap allocated Str object
// (same general idea as a Java String, but in C++)
// (init here with copy constructor; destructor called when Str deleted)
// (uses overloaded << operator for Str)
Str* h = new Str(hello);
h->append(" cse333!");
cout << "Str at " << h << " = \"" << *h << "\"" << endl;
cout << " length is " << h->length() << endl;
delete h;
here(6);
// Enough already!!
return EXIT_SUCCESS;
}