3月30及31日学习心得

这两天主要学习了14.1-14.7,即重载运算符的操作。大体来说几乎所有运算符都可以重载,不能被重载的运算符有:: .* . ? :

通常情况不重载的运算符有:逗号,取地址,逻辑与和逻辑或。

确定到底是函数实现,还是运算符实现的原则是:只有当操作的含义对于用户来说清晰明了时才可以使用运算符。如果用户对运算符可能有几种不同的理解,则使用这样的运算符将产生二义性。

下面的准则我将有助于我们在将运算符定义为成员函数还是普通的非成员函数做出抉择:

1.赋值,下标,调用和成员访问箭头运算符必须是成员。

2复合赋值运算符一般来说是成员,但非必须

3.改变对象状态的运算符或者与给定类型密切相关的运算符,例如:递增递减和解应用等,通常应该是成员。

4.具有对称性的运算符可能转换为一端的运算对象,如算术,相等性、关系和位运算等,通常为非成员函数。

14.2

  输入和输出运算符<< >>必须为非成员函数,其中输入必须检查输入是否成功。并且当输入运算符发生错误时,要负责恢复。

14.3

  如果类同时定义了算术运算符和相关的复合赋值运算符,则通常情况应使用复合赋值。

  使用==的前提条件是要有一种逻辑相等关系。

  如果存在一种可靠的<定义,则应考虑为这个类定义<运算符,且与==对应。

14.4

  重载的赋值运算符通常用于实现{}初始化。<initializer_list<xx>>

  但今天在对StrBlob使用时发生错误。

14.5

 下标运算符必须为成员函数。

 如果一个类包含下标成员,则它通常会定义两个版本:一个返回普通引用,另一个是常量成员并返回常量应用

 但今天在返回 const char & 时报错,估计是引用的问题。

14.6

 递增和递减运算符都要求前置和后置版本,一般是先定义前置,返回引用。后置返回普通类型,并使用前置带来的便利。通过一个无用的int参数来区分前后置。

14.7

箭头运算符必须是函数成员,解引通常也是成员函数。

以下是几个实例

#ifndef STRBLOB_H
#define STRBLOB_H
#include <vector>
#include <string>
#include <memory>
#include <stdexcept>
using namespace::std;
// forward declaration needed for friend declaration in StrBlob
class StrBlobPtr;

class StrBlob {
	friend class StrBlobPtr;
public:
    typedef std::vector<std::string>::size_type size_type;

	// constructors
    StrBlob() : data(new std::vector<std::string>()) { }
	// pre C++11 no initializer_list, we'll define a constructor
	// that takes pointers to an array instead
    StrBlob(const std::string*, const std::string*);
    string& operator[](size_t); 

	// size operations
    size_type size() const { return data->size(); }
    bool empty() const { return data->empty(); }

    // add and remove elements
    void push_back(const std::string &t) { data->push_back(t); }
    void pop_back();

    // element access
    std::string& front();
    std::string& back();

	// interface to StrBlobPtr
	StrBlobPtr begin();  // can't be defined until StrBlobPtr is
    StrBlobPtr end();
private:
    std::shared_ptr<std::vector<std::string> > data; 
    // throws msg if data[i] isn't valid
    void check(size_type i, const std::string &msg) const;
};

// constructor
inline
StrBlob::StrBlob(const std::string *beg, const std::string *end): 
       data(new std::vector<std::string>(beg, end)) { }

// StrBlobPtr throws an exception on attempts to access a nonexistent element 
class StrBlobPtr {
	friend bool eq(const StrBlobPtr&, const StrBlobPtr&);
public:
    StrBlobPtr(): curr(0) { }
    StrBlobPtr(StrBlob &a, size_t sz = 0): wptr(a.data), curr(sz) { }

    std::string& deref() const;
    StrBlobPtr& incr();       // prefix version
    StrBlobPtr& decr();       // prefix version
    
    StrBlobPtr& operator++();//pre
	StrBlobPtr& operator--();//pre
	StrBlobPtr operator++(int);
	StrBlobPtr operator--(int);
	string& operator*() const
	{
		auto p=check(curr,"deference past end");
		return (*p)[curr];
	}
	string* operator->() const
	{
		return &this->operator*();
	}
private:
    // check returns a shared_ptr to the vector if the check succeeds
    std::shared_ptr<std::vector<std::string> > 
        check(std::size_t, const std::string&) const;

    // store a weak_ptr, which means the underlying vector might be destroyed
    std::weak_ptr<std::vector<std::string> > wptr;  
    std::size_t curr;      // current position within the array
};

inline
std::string& StrBlobPtr::deref() const
{
    std::shared_ptr<std::vector<std::string> >
			 p = check(curr, "dereference past end"); 
    return (*p)[curr];  // (*p) is the vector to which this object points
}

inline
std::shared_ptr<std::vector<std::string> > 
StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
	// is the vector still around?
    std::shared_ptr<std::vector<std::string> > ret = wptr.lock();   
    if (!ret)
        throw std::runtime_error("unbound StrBlobPtr");

    if (i >= ret->size()) 
        throw std::out_of_range(msg);

    return ret; // otherwise, return a shared_ptr to the vector
}

// prefix: return a reference to the incremented object
inline
StrBlobPtr& StrBlobPtr::incr()
{
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment past end of StrBlobPtr");
    ++curr;       // advance the current state
    return *this;
}

inline
StrBlobPtr& StrBlobPtr::decr()
{
    // if curr is zero, decrementing it will yield an invalid subscript
    --curr;       // move the current state back one element}
    check(-1, "decrement past begin of StrBlobPtr");
    return *this;
}

// begin and end members for StrBlob
inline
StrBlobPtr
StrBlob::begin() 
{
	return StrBlobPtr(*this);
}

inline
StrBlobPtr
StrBlob::end() 
{
	StrBlobPtr ret = StrBlobPtr(*this, data->size());
    return ret; 
}

// named equality operators for StrBlobPtr
inline
bool eq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	std::shared_ptr<std::vector<std::string> > 
		 l = lhs.wptr.lock(), r = rhs.wptr.lock();
	// if the underlying vector is the same 
	if (l == r) 
		// then they're equal if they're both null or 
		// if they point to the same element
		return (!r || lhs.curr == rhs.curr);
	else
		return false; // if they point to difference vectors, they're not equal
}

inline
bool neq(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
	return !eq(lhs, rhs); 
}
inline
StrBlobPtr& StrBlobPtr::operator++()
{
	check(curr,"increment past end of StrBlob");
	++curr;
	return *this;
}
inline
StrBlobPtr& StrBlobPtr::operator--()
{
	--curr;
	check(curr,"decrement past begin of StrBlobPtr");
	return *this;
}
inline
StrBlobPtr StrBlobPtr::operator++(int)
{
	StrBlobPtr ret=*this;
	++*this;
	return ret;
}
inline
StrBlobPtr StrBlobPtr::operator--(int)
{
	StrBlobPtr ret=*this;
	--*this;
	return ret;
}
#endif


2.

#include <cstring>
using std::strlen;

#include <algorithm>
using std::copy; 

#include <cstddef>
using std::size_t; 

#include <iostream>
using std::ostream; 

#include <utility>
using std::swap;

#include <memory>
using std::uninitialized_copy;

#include "String.h"

// define the static allocator member
std::allocator<char> String::a;

// copy-assignment operator
String & String::operator=(const String &rhs)
{
	// copying the right-hand operand before deleting the left handles self-assignment
    char *newp = a.allocate(rhs.sz); // copy the underlying string from rhs
	uninitialized_copy(rhs.p, rhs.p + rhs.sz, newp);

	if (p)
		a.deallocate(p, sz); // free the memory used by the left-hand operand
	p = newp;    // p now points to the newly allocated string
	sz = rhs.sz; // update the size

    return *this;     
}

String& String::operator=(const char *cp)
{
	if (p) a.deallocate(p, sz);
	p = a.allocate(sz = strlen(cp));
	uninitialized_copy(cp, cp + sz, p);
	return *this;
}

String& String::operator=(char c)
{
	if(p) a.deallocate(p, sz);
	p = a.allocate(sz = 1);
	*p = c;
	return *this;
}

// named functions for operators
ostream &print(ostream &os, const String &s)
{
	const char *p = s.begin();
	while (p != s.end())
		os << *p++ ;
	return os;
}

String add(const String &lhs, const String &rhs) 
{
	String ret;
	ret.sz = rhs.size() + lhs.size();   // size of the combined String
	ret.p = String::a.allocate(ret.sz); // allocate new space
	uninitialized_copy(lhs.begin(), lhs.end(), ret.p); // copy the operands
	uninitialized_copy(rhs.begin(), rhs.end(), ret.p + lhs.sz);
	return ret;  // return a copy of the newly created String
}
	
// return plural version of word if ctr isn't 1
String make_plural(size_t ctr, const String &word,
                               const String &ending)
{
        return (ctr != 1) ?  add(word, ending) : word;
}

// chapter 14 will explain overloaded operators
ostream &operator<<(ostream &os, const String &s)
{
	return print(os, s);
}

String operator+(const String &lhs, const String &rhs) 
{
	return add(lhs, rhs);
}
char& String::operator[](size_t n)
	{
		auto c=p+n;
		return *c;
	}


3.

#ifndef STRVEC_H
#define STRVEC_H
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <initializer_list>
#include <deque>
#include <list>
#include <array>
#include <forward_list>
#include <sstream>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
#include <memory>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

using namespace::std;
class StrVec {
public:
	StrVec() :
		elements(nullptr), first_free(nullptr), cap(nullptr) { }
	StrVec(initializer_list<string> sl)
	{
		for (auto i : sl)
			push_back(i);
	}
	StrVec(const StrVec&);
	StrVec &operator=(const StrVec&);
	StrVec &operator=(initializer_list<string> il)
	{
		auto temp=alloc_n_copy(il.begin(),il.end());
		free();
		elements=temp.first;
		first_free=cap=temp.second;
		return *this;
	}
	StrVec &operator+=(const StrVec &str)
	{
		for(auto c=str.begin();c!=str.end();++c)
		{
			push_back(*c);
		}
		return *this;
	}
	bool operator==(const StrVec& rhs)
	{
		bool judge=true;
		if(size()==0)
		{
			if(rhs.size()!=0)
			judge=false;
		}
		else
		{
		for(auto i=begin(),j=rhs.begin();i!=end();++i,++j)
		{
			if(j==rhs.end())
			{
				judge=false;
				break;
			}
			if(*i!=*j)
			{
				judge=false;
				break;
			}
		}
	}
		return judge;
	}
	bool operator!=(const StrVec& rhs)
	{
		return !(*this == rhs);
	}
	bool operator<(const StrVec& rhs)
	{
		return size()<rhs.size();
	}
	string& operator[](size_t n)
	{
		return elements[n];
	}
	const string& operator[](size_t n) const
	{
		return elements[n];
	}
	~StrVec();
	void push_back(const string &);
	size_t size() const { return first_free - elements; }
	size_t capacity() const { return cap - elements; }
	string* begin() const { return elements; }
	string* end() const { return first_free; }
private:
	allocator<string> alloc;
	void chk_n_alloc() {
		if (size() == capacity())
			reallocate();
	}
	pair<string *, string *> alloc_n_copy(const string *, const string *);
	void free();
	void myfree();
	void reallocate();
	string* elements;
	string* first_free;
	string* cap;
};
#endif
#include "StrVec.h"
void StrVec::push_back(const string& s)
{
	chk_n_alloc();
	alloc.construct(first_free++, s);
}

pair<string *, string *> StrVec::alloc_n_copy(const string *b, const string *e)
{
	auto data = alloc.allocate(e - b);
	return { data,uninitialized_copy(b,e,data) };
}

void StrVec::free()
{
	if (elements) {
		for (auto p = first_free; p != elements;)
			alloc.destroy(--p);
		alloc.deallocate(elements, cap - elements);
	}
}

void StrVec::myfree()
{
	if (elements)
	{
		for_each(elements, first_free, [this](string &rhs) {alloc.destroy(&rhs); });
		alloc.deallocate(elements, cap - elements);
	}
}

StrVec::StrVec(const StrVec &s)
{
	auto newdata = alloc_n_copy(s.begin(), s.end());
	elements = newdata.first;
	first_free = cap = newdata.second;
}

StrVec::~StrVec()
{
	free();
}

StrVec& StrVec::operator=(const StrVec &rhs)
{
	auto data = alloc_n_copy(rhs.begin(), rhs.end());
	free();
	elements = data.first;
	cap = first_free = data.second;
	return *this;
}

void StrVec::reallocate()
{
	auto newcapacity = size() ? 2 * size() : 1;
	auto newdata = alloc.allocate(newcapacity);
	auto dest = newdata;
	auto elem = elements;
	for (auto i = 0; i != size(); ++i)
		alloc.construct(dest++, std::move(*elem++));
	free();
	elements = newdata;
	first_free = dest;
	cap = elements + newcapacity;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值