Wednesday, March 12, 2003

Making class objects act like values (K&M -- Chapter 12)

The following code uses the Vec class, which was implemented in Chapter 11, in order to implement a string-like class called Str. At the core of the implementation of the Str class is a private data member which is defined as a vector of characters (i.e. Vec<char> data).

Class declaration for the Str class


#ifndef STR_H
#define STR_H

#include <algorithm>
#include <cstring>
#include <iterator>

#include "Vec.h"

class Str {
	// input operator implemented in 12.3.2/216
	friend std::istream& operator>>(std::istream&, Str&);
public:
	typedef Vec<char>::size_type size_type;
	typedef char* iterator;
	typedef const char* const_iterator;

	Str() { }
	Str(size_type n, char c): data(n, c) { }
	Str(const char* cp) {
		std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
	}
	template <class In> Str(In i, In j) {
		std::copy(i, j, std::back_inserter(data));
	}

	char& operator[](size_type i) { return data[i]; }
	const char& operator[](size_type i) const { return data[i]; }
	size_type size() const { return data.size(); }

	iterator begin() { return data.begin(); }
	const_iterator begin() const { return data.begin(); }

	iterator end() { return data.end(); }
	const_iterator end() const { return data.end(); }

	Str& operator+=(const Str& s) {
		std::copy(s.data.begin(), s.data.end(),
		          std::back_inserter(data));
		return *this;
	}

private:
	Vec<char> data;
};

// output operator implemented in 12.3.2/216
std::ostream& operator<<(std::ostream&, const Str&);

// String concatentation operator.
Str operator+(const Str&, const Str&);

inline bool operator<(const Str& lhs, const Str& rhs)
{
	return std::lexicographical_compare(lhs.begin(), lhs.end(),
					    rhs.begin(), rhs.end());
}

// Other relational operators (e.g. >, <=, >=) can be implemented similarly.

inline bool operator==(const Str& lhs, const Str& rhs)
{
	return lhs.size() == rhs.size() &&
		std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
inline bool operator!=(const Str& lhs, const Str& rhs)
{
	return !(lhs == rhs);
}

#endif



Class implementation for the Str class


#include <cctype>
#include <iostream>

using std::isspace;

#include "Str.h"

using std::istream;
using std::ostream;

Str operator+(const Str& s, const Str& t)
{
	Str r = s;
	r += t;
	return r;
}

ostream& operator<<(ostream& os, const Str& s)
{
	for (Str::size_type i = 0; i != s.size(); ++i)
		os << s[i];
	return os;
}

istream& operator>>(istream& is, Str& s)
{
	// obliterate existing value(s)
	s.data.clear();

	// read and discard leading whitespace
	char c;
	while (is.get(c) && isspace(c))
		;	// nothing to do, except testing the condition

	// if still something to read, do so until next whitespace character
	if (is) {
		do
			// Note that 'data' is private in class 'Str'.
			// Therefore 'istream& operator>>(istream& is, Str& s)'
			// must be declared as a friend in the Str class.
			s.data.push_back(c);
		while (is.get(c) && !isspace(c));

		// if we read whitespace, then put it back on the stream
		if (is)
			is.unget();
	}

	return is;
}


Last modified: Wed Mar 12 14:04:43 2003