C++Primer14.2.1节练习

练习14.6:

#include <iostream>
#include <string>
#include <errno.h>
using namespace std;

class Sales_date {
	//将非成员重载函数设置为友元函数
	friend Sales_date operator+(const Sales_date& h1, const Sales_date& h2);
	friend istream& operator >> (istream& is, Sales_date& item);
	friend ostream& operator << (ostream& os, const Sales_date& item);
public:
	//默认构造函数
	Sales_date():bookNo(std::string()){ }
	Sales_date(const std::string& s, unsigned us, double p):bookNo(s), units_sold(us), revenue(p*us) { }
	Sales_date(const std::string& s) :bookNo(s) { }
	//拷贝构造函数
	Sales_date(const Sales_date& s):bookNo(s.bookNo), units_sold(s.units_sold), revenue(s.revenue){ }
	//拷贝赋值运算符
	Sales_date& operator=(const Sales_date&);

	//复合赋值运算符
	Sales_date& operator+=(const Sales_date&);

	//得到bookNo
	std::string isbn()const { return bookNo; }

private:
	//平均售价
	double avg_price()const { return units_sold ? revenue / units_sold : 0; }
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};

//拷贝赋值运算符
Sales_date& Sales_date::operator=(const Sales_date& s)
{
	bookNo = s.bookNo;
	units_sold = s.units_sold;
	revenue = s.revenue;

	return *this;
}

//复合赋值运算符
Sales_date& Sales_date::operator+=(const Sales_date& s)
{
	if (this->bookNo == s.bookNo)
	{
		units_sold = units_sold + s.units_sold;
		revenue = revenue + s.revenue;
		return *this;
	}
	else
	{
		throw runtime_error("bookNo is different");
	}
}

//重载的加法运算符
Sales_date operator+(const Sales_date& h1, const Sales_date& h2)
{
	if (h1.bookNo == h2.bookNo)
	{
		Sales_date sTemp = h1;
		sTemp.units_sold = sTemp.units_sold + h2.units_sold;
		sTemp.revenue = sTemp.revenue + h2.revenue;
		return sTemp;
	}
	else
	{
		//无法相加
		throw runtime_error("bookNo is different");
	}

}

//重载输入运算符
istream& operator >> (istream& is, Sales_date& item)
{
	double price;
	is >> item.bookNo >> item.units_sold >> price;
	//检查输入是否出错
	if (is)
	{
		item.revenue = item.units_sold * price;
	}
	else
	{
		//输入失败,对象被赋予默认的状态
		item = Sales_date();
	}
	return is;
}

//重载输出运算符
ostream& operator << (ostream& os, const Sales_date& item)
{
	os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
	return os;
}


//测试
int main()
{
	Sales_date s1("Machine Learnig", 20, 10);
	cout << s1 << endl;
	system("pause");
	return 0;
}

结果:

 练习14.7:

#include <iostream>
#include <string>
using namespace std;
#include <algorithm>
#include <fstream>
#include <memory>
#include <set>
#include <map>
#include <sstream>
#include <vector>



//标准库string的简化实现
class String{
	//将输出重载运算符函数定义为友元
	friend ostream& operator<<(ostream& os, const String& s);
public:
	//默认初始化
	String();
	//接受C风格字符串指针参数
	String(const char*);
	//接受初始值列表的构造函数
	String(initializer_list<char>);
	//拷贝构造函数
	String(const String&);
	//拷贝赋值运算符
	String& operator=(const String&);
	//移动构造函数
	String(String&&)noexcept;
	//移动赋值运算符
	String& operator=(String&&)noexcept;
	//析构函数
	~String();
	//添加元素
	void push_back(const char&);
	//移动元素
	void push_back(char&&);
	//数组大小和容量
	size_t size()const;
	size_t capacity()const;
	//获得数组的首元素和尾后元素
	char* begin()const;
	char* end()const;

	void reserve(size_t n);
	void resize(size_t n);

private:
	//静态成员,用来分配元素,工具人,不需要每个对象都分配,设置为静态成员
	static std::allocator<char>alloc;
	//工具函数,被添加元素的函数所使用
	void chk_n_alloc();
	//工具函数,被拷贝构造函数、赋值运算符和析构函数使用
	std::pair<char*, char*>alloc_n_copy(const char*, const char*);
	void free();
	//获得更多内存并拷贝已有元素
	void reallocate();
	//指向数组首元素的指针
	char* elements;
	//指向数组第一个空闲元素的指针
	char* first_free;
	//指向数组尾后位置的指针
	char* cap;
};

//静态成员变量需要在类外定义,但不一定要初始化
std::allocator<char> String::alloc;

//reallocate成员
void String::reallocate()
{
	//分配当前大小两倍的内存空间
	auto newCapacity = size() ? 2 * size() : 1;
	//分配新内存
	auto newData = alloc.allocate(newCapacity);
	//将数据从旧内存移到新内存
	//指向数组下一个空闲位置
	auto dest = newData;
	//指向旧数组中下一个元素
	auto elem = elements;
	for (size_t i = 0; i != size(); ++i)
	{
		alloc.construct(dest++, std::move(*elem++));
	}
	//一旦我们移动完元素就释放旧内存空间
	free();
	//更新我们的数据结构,执行新元素
	elements = newData;
	first_free = dest;
	cap = elements + newCapacity;

}

size_t String::capacity()const
{
	return cap - elements;
}

void String::chk_n_alloc()
{
	if (size() == capacity())
	{
		reallocate();
	}
}

size_t String::size()const
{
	return first_free - elements;
}

char* String::begin()const
{
	return elements;
}

char* String::end()const
{
	return first_free;
}

//push_back
void String::push_back(const char& c)
{
	chk_n_alloc();	
	//此时有足够的空间,创建元素,拷贝
	alloc.construct(first_free++, c);
}

//移动元素
void String::push_back(char&& c)
{
	chk_n_alloc();
	//此时有足够的空间,移动元素
	alloc.construct(first_free++, std::move(c));
}

//工具函数,被拷贝构造函数、赋值运算符和析构函数使用
pair<char*, char*> String::alloc_n_copy(const char* c1, const char* c2)
{
	//拷贝传递参数指定范围的元素
	//创建元素的副本
	auto data = alloc.allocate(c2 - c1);
	//uninitialized_copy(b,e,b2)作用是从迭代器b和e指出的输出范围中拷贝元素到迭代器b2指定的未构造的原始内存中
	// 使用uninitialized_copy(b,e,b2)函数对未构造的函数进行拷贝
	//返回一个pair,分别指向拷贝后的数组首元素和最后元素后面的元素
	return { data,uninitialized_copy(c1,c2,data) };
}


//free
void String::free()
{
	//不能传递给deallocate一个空指针,如果elements为空,函数就什么也不做
	if (elements)
	{
		for_each(elements, first_free, [](char& p) {alloc.destroy(&p); });
		alloc.deallocate(elements, cap - elements);
	}
}

//默认初始化
String::String() :elements(nullptr), first_free(nullptr), cap(nullptr)
{

}

//接受C风格字符串指针参数
String::String(const char* str)
{
	//确定数组大小
	auto newCapacity = strlen(str);
	//创建内存
	auto newData = alloc.allocate(newCapacity);
	elements = newData;
	//复制元素
	auto p = uninitialized_copy(str, str + newCapacity, newData);
	//更新指针
	first_free = p;
	cap = elements + newCapacity;
}

//拷贝构造函数
String::String(const String& cv)
{
	//调用alloc_n_copy分配空间以容纳与sv中一样多的元素
	auto newData = alloc_n_copy(cv.begin(), cv.end());
	elements = newData.first;
	first_free = cap = newData.second;

	cout << "copy construct function" << endl;
}

//拷贝赋值运算符
String& String::operator=(const String& cv)
{
	//为了正确处理自赋值,在释放已有元素前调用alloc_n_copy
	//分配内存,大小和sv中占用的元素一样多
	auto data = alloc_n_copy(cv.begin(), cv.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
	cout << "copy assignment operator" << endl;
	return *this;
}

//接受初始值列表的构造函数
String::String(initializer_list<char>l)
{
	//使用alloc_n_copy赋值元素,创建内存
	auto newData = alloc_n_copy(l.begin(), l.end());
	elements = newData.first;
	first_free = newData.second;
}

//移动构造函数
String::String(String&& s)noexcept:elements(s.elements),first_free(s.first_free),cap(s.cap)
{
	//令移后源对象进入状态-----对其运行析构函数是安全的
	s.elements = s.first_free = s.cap = nullptr;
	cout << "------String move constructor------" << endl;
}

//移动赋值运算符
String& String::operator=(String&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		first_free = rhs.first_free;
		cap = rhs.cap;
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	cout << "------String move assignment operator------" << endl;
	return *this;
}


//析构函数
String::~String()
{
	free();
}

void String::reserve(size_t n)
{
	//分配大小为n的内存
	if (capacity() < n)
	{
		auto newCapacity = n;
		//创建新内存
		auto newData = alloc.allocate(n);
		//将数据从旧内存移到新内存
		//指向数组下一个空闲位置
		auto dest = newData;
		//指向旧数组中下一个元素
		auto elem = elements;
		//将数据移动
		for (size_t i = 0; i != size(); ++i)
		{
			alloc.construct(dest++, std::move(*elem));
		}
		//一旦我们移动完元素就释放旧内存空间
		free();
		//更新我们的数据结构,执行新元素
		elements = newData;
		first_free = dest;
		cap = elements + newCapacity;
	}
}

void String::resize(size_t n)
{
	//n的大小大于size(),以默认值填充
	if (size() < n)
	{
		size_t num = n - size();
		for (size_t i = 0; i != num; ++i)
		{
			alloc.construct(first_free++, char());
		}
	}


	//n的大小小于size(),删除
	if (size() > n)
	{
		//从n开始destory内存
		for (auto p = elements + n; p != first_free; ++p)
		{
			alloc.destroy(p);
		}
		//更新first_free
		first_free = elements + n;
	}
}

//重载输出运算符
ostream& operator<<(ostream& os, const String& s)
{
	for (auto c : s)
	{
		os << c;
	}
	return os;
}

int main()
{
	//测试
	String s1("hello ");
	String s2("world!!!");
	String s3("C++");
	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	system("pause");
	return 0;
}

结果如下:

练习14.8:

 与14.7类似,略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白学C++.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值