cppPrimer学习14th
cppPrimer学习14th
目录
从章节14.8开始看
14.1
在什么情况下重载的运算符与内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样?
不同点:
重载运算符 至少有一个参数为类
重载运算符的求值顺序不一定相同,比如 && || 会依次求值
相同点:
优先级和结核性相同
14.2
// 为Sales_data 重载输入,输出,加法和复合赋值
// 为Sales_data 重载输入,输出,加法和复合赋值
#include <iostream>
#include <string>
//using namespace std;
using std::cin;
using std::cout;
using std::endl;
using std::istream;
using std::ostream;
using std::string;
class Sales_data
{
friend ostream &operator<<(ostream &o, const Sales_data &d);
friend istream &operator>>(istream &o, Sales_data &d);
friend Sales_data operator+(Sales_data &a, Sales_data &b);
public:
Sales_data(const string &bookNo, unsigned units, double revenue) : bookNo(bookNo), units_sold(units), revenue(revenue)
{
}
Sales_data() : bookNo("default id"), units_sold(0), revenue(0) {}
Sales_data &operator+=(const Sales_data &b)
{
units_sold += b.units_sold;
revenue += b.revenue;
}
private:
std::string bookNo; // name
unsigned units_sold = 0; //售卖的数量
double revenue = 0.0; //售卖的总价
double GetAvg() const
{
return units_sold ? revenue / units_sold : 0;
}
};
ostream &operator<<(ostream &o, const Sales_data &d)
{
o << d.bookNo << ": " << d.units_sold << "," << d.revenue << "," << d.GetAvg() << endl;
}
istream &operator>>(istream &o, Sales_data &d)
{
cout << "pls input bookNo ,units_sold, revenue" << endl;
o >> d.bookNo >> d.units_sold >> d.revenue;
if (!o)
d = Sales_data();
}
Sales_data operator+(Sales_data &a, Sales_data &b)
{
return Sales_data(a.bookNo, a.units_sold + b.units_sold, a.revenue + b.revenue);
}
int main(int argc, char const *argv[])
{
Sales_data book1("ID1001", 10, 38);
cout << book1 << endl;
Sales_data book2("ID1002", 10, 40);
cout << book2 << endl;
Sales_data book3 = book1 + book2;
cout << book3 << endl;
book3 += book2;
cout << book3 << endl;
cin >> book1;
cout << book1 << endl;
while (1)
;
return 0;
}
14.3
string和vector都定义了重载的==以比较各自的对象,
假设svec1和svec2是存放string的vector,确定在下面的表达式中分别使用了哪个版本的==?
(a) "cobble" == "stone" 这里比较的是 char*
(b) svec1[0] ==svec2[0] string
(c) svec1 ==svec2 vector
(d) svec[0] == "stone" string
14.4
如何确定下列运算符是否应该是类的成员?
(a) % 非
(b) %= 是
(c) ++ 是
(d) -> 是
(e) << 非
(f) && 非
(g) == 是
(h) () 是
14.5
/*
14.5 在7.5.1节的练习7.40中,编写了下列类中的某一个框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a)Book (b)Date (c)Employee (d)Vehicle (e)Object (f)Tree
*/
#include <iostream>
#include <iomanip>
class Date
{
private:
int year = 2000;
int month = 1;
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
public:
Date(int y, int m, int d, int h, int mi, int s) : year(y), month(m), day(d), hour(h), min(mi), sec(s) {}
friend std::ostream &operator<<(std::ostream &o, Date &d);
};
std::ostream &operator<<(std::ostream &o, Date &d)
{
return o << d.year << "-" << d.month << "-" << d.day << " " << d.hour << ":" << d.min << ":" << d.sec;
}
int main(int argc, const char **argv)
{
Date d(2020, 4, 9, 14, 17, 5);
std::cout << d << std::endl;
while (1)
;
return 0;
}
14.6
参考14.2
14.7
class String
{
public:
String();
String(const char *str);
friend ostream& operator<<(ostream &os, const String &str);
private:
char *str;
};
ostream& operator<<(ostream &os, const String &str)
{
cout << str;
return os;
}
14.8
参考14.5
14.9
参考14.2
14.10
a 正常构造
b 默认构造
14.11
price 可能未定义
14.12
/*
14.12 你在7.5.1节的练习中曾经选择并编写了一个类,为它定义一个输入运算符并确保该运算符可以处理输入错误。
14.5 在7.5.1节的练习7.40中,编写了下列类中的某一个框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a)Book (b)Date (c)Employee (d)Vehicle (e)Object (f)Tree
*/
#include <iostream>
#include <iomanip>
class Date
{
private:
int year = 2000;
int month = 1;
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
public:
Date() = default;
Date(int y, int m, int d, int h, int mi, int s) : year(y), month(m), day(d), hour(h), min(mi), sec(s) {}
friend std::ostream &operator<<(std::ostream &o, Date &d);
friend std::istream &operator>>(std::istream &i, Date &d);
};
std::ostream &operator<<(std::ostream &o, Date &d)
{
return o << d.year << "-" << d.month << "-" << d.day << " " << d.hour << ":" << d.min << ":" << d.sec;
}
std::istream &operator>>(std::istream &o, Date &ret)
{
Date d;
if (o >> d.year >> d.month >> d.day >> d.hour >> d.min >> d.sec)
{
ret = d;
}
else
{
ret = Date();
o.clear();
o.sync();
}
}
int main(int argc, const char **argv)
{
Date d(2020, 4, 9, 14, 17, 5);
std::cout << d << std::endl;
while (1)
{
std::cout << "pls input date" << std::endl;
std::cin >> d;
std::cout << d << std::endl;
}
while (1)
;
return 0;
}
14.13
减法
Sales_data operator-(Sales_data &a, Sales_data &b)
{
return Sales_data(a.bookNo, a.units_sold - b.units_sold, a.revenue - b.revenue);
}
Sales_data &operator-=(const Sales_data &b)
{
units_sold -= b.units_sold;
revenue -= b.revenue;
}
14.14
你觉得为什么调用operator+=来定义operator+比其他方法要更有效?
性能上没有优势,而可读性上后者显然更好。
14.17
/*
14.17 重载== 和 !=
14.12 你在7.5.1节的练习中曾经选择并编写了一个类,为它定义一个输入运算符并确保该运算符可以处理输入错误。
14.5 在7.5.1节的练习7.40中,编写了下列类中的某一个框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a)Book (b)Date (c)Employee (d)Vehicle (e)Object (f)Tree
*/
#include <iostream>
#include <iomanip>
class Date
{
private:
int year = 2000;
int month = 1;
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
public:
friend std::ostream &operator<<(std::ostream &o, Date &d);
friend std::istream &operator>>(std::istream &i, Date &d);
friend bool operator!=(const Date &t, const Date &d);
friend bool operator==(const Date &t, const Date &d);
Date() = default;
Date(int y, int m, int d, int h, int mi, int s) : year(y), month(m), day(d), hour(h), min(mi), sec(s) {}
};
std::ostream &operator<<(std::ostream &o, Date &d)
{
return o << d.year << "-" << d.month << "-" << d.day << " " << d.hour << ":" << d.min << ":" << d.sec;
}
std::istream &operator>>(std::istream &o, Date &ret)
{
Date d;
if (o >> d.year >> d.month >> d.day >> d.hour >> d.min >> d.sec)
{
ret = d;
}
else
{
ret = Date();
o.clear();
o.sync();
}
}
bool operator==(const Date &t, const Date &d)
{
return t.year == d.year && t.month == d.month && t.day == d.day && t.hour == d.hour && t.min == d.min && t.sec == d.sec;
}
bool operator!=(const Date &t, const Date &d)
{
return !(t == d);
}
int main(int argc, const char **argv)
{
Date a(2020, 4, 9, 14, 17, 5);
std::cout << a << std::endl;
Date b(2020, 1, 9, 14, 17, 5);
std::cout << b << std::endl;
std::cout << std::boolalpha << (a == b) << std::endl;
std::cout << std::boolalpha << (a != b) << std::endl;
// while (1)
// {
// std::cout << "pls input date" << std::endl;
// std::cin >> d;
// std::cout << d << std::endl;
// }
while (1)
;
return 0;
}
14.19
/*
14.19 你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有关系运算符吗?如果是,请实现它;如果不是,解释原因
14.17 重载== 和 !=
14.12 你在7.5.1节的练习中曾经选择并编写了一个类,为它定义一个输入运算符并确保该运算符可以处理输入错误。
14.5 在7.5.1节的练习7.40中,编写了下列类中的某一个框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a)Book (b)Date (c)Employee (d)Vehicle (e)Object (f)Tree
*/
#include <iostream>
#include <iomanip>
class Date
{
private:
int year = 2000;
int month = 1;
int day = 1;
int hour = 0;
int min = 0;
int sec = 0;
public:
friend std::ostream &operator<<(std::ostream &o, Date &d);
friend std::istream &operator>>(std::istream &i, Date &d);
friend bool operator!=(const Date &t, const Date &d);
friend bool operator==(const Date &t, const Date &d);
friend bool operator>(const Date &t, const Date &d);
friend bool operator>=(const Date &t, const Date &d);
friend bool operator<(const Date &t, const Date &d);
friend bool operator<=(const Date &t, const Date &d);
Date() = default;
Date(int y, int m, int d, int h, int mi, int s) : year(y), month(m), day(d), hour(h), min(mi), sec(s) {}
};
std::ostream &operator<<(std::ostream &o, Date &d)
{
return o << d.year << "-" << d.month << "-" << d.day << " " << d.hour << ":" << d.min << ":" << d.sec;
}
std::istream &operator>>(std::istream &o, Date &ret)
{
Date d;
if (o >> d.year >> d.month >> d.day >> d.hour >> d.min >> d.sec)
{
ret = d;
}
else
{
ret = Date();
o.clear();
o.sync();
}
}
bool operator==(const Date &t, const Date &d)
{
return t.year == d.year && t.month == d.month && t.day == d.day && t.hour == d.hour && t.min == d.min && t.sec == d.sec;
}
bool operator!=(const Date &t, const Date &d)
{
return !(t == d);
}
bool operator>(const Date &t, const Date &d)
{
return ((t.year > d.year) ||
(t.year == d.year && t.month > d.month) ||
(t.year == d.year && t.month == d.month && t.day > d.day) ||
(t.year == d.year && t.month == d.month && t.day == d.day && t.hour > d.hour) ||
(t.year == d.year && t.month == d.month && t.day == d.day && t.hour == d.hour && t.min > d.min) ||
(t.year == d.year && t.month == d.month && t.day == d.day && t.hour == d.hour && t.min == d.min && t.min > d.min));
}
bool operator>=(const Date &t, const Date &d)
{
return t > d || t == d;
}
bool operator<(const Date &t, const Date &d)
{
return !(t >= d);
}
bool operator<=(const Date &t, const Date &d)
{
return !(t > d);
}
int main(int argc, const char **argv)
{
Date a(2020, 4, 9, 14, 17, 1);
Date b(2020, 4, 9, 14, 17, 2);
std::cout << std::boolalpha << (a > b) << std::endl;
std::cout << std::boolalpha << (a >= b) << std::endl;
std::cout << std::boolalpha << (a < b) << std::endl;
std::cout << std::boolalpha << (a <= b) << std::endl;
std::cout << std::boolalpha << (a >= a) << std::endl;
std::cout << std::boolalpha << (a < a) << std::endl;
// while (1)
// {
// std::cout << "pls input date" << std::endl;
// std::cin >> d;
// std::cout << d << std::endl;
// }
while (1)
;
return 0;
}
14.20
14.21
+= 执行加法,+调用+= 的优势在于好看一点
// + 调用 +=
// Sales_data operator+(Sales_data &a, Sales_data &b)
// {
// //return Sales_data(a.bookNo, a.units_sold + b.units_sold, a.revenue + b.revenue);
// Sales_data t = a;
// t += b;
// return t;
// }
// Sales_data &Sales_data::operator+=(const Sales_data &b)
// {
// units_sold += b.units_sold;
// revenue += b.revenue;
// return *this;
// }
// += 调用+
Sales_data operator+(const Sales_data &a, const Sales_data &b)
{
Sales_data t = a;
t.units_sold += b.units_sold;
t.revenue += b.revenue;
return t;
}
Sales_data &Sales_data::operator+=(const Sales_data &b)
{
*this = *this + b;
return *this;
}
14.22
/*
14.22:定义赋值运算符的一个新版本,使得我们能把一个表示ISBN的string赋给一个Sales_data对象
*/
Sales_data &operator=(const std::string &s)
{
bookNo = s;
return *this;
}
14.23
//14.23:为你的StrVec类定义一个initializer_list赋值运算符
StrVec &StrVec::operator=(initializer_list<string> li)
{
auto data = allc_n_copy(li.begin(), li.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
14.24
// 14.24:你在7.5.1节的7.40中曾经选择并编写了一个类,你认为它应该含有拷贝赋值和移动赋值运算符吗?
// 如果是,请实现它们
date 不需要,没有指针相关的
14.25
//14.25上题的这个类还需要定义其他赋值运算符吗?如果是,请实现它们;同时说明运算对象应该是什么类型并解释原因
// string > date
Date &Date::operator=(const std::string &s)
{
std::istringstream in(s);
in >> *this;
return *this;
}
14.29
为什么不定义const版本的递增和递减运算符
因为会改变对象的值
14.33
一个重载的函数调用运算符应该接受几个运算对象
0个或者多个,和普通函数一样,上限这个不去细究
14.34
//定义一个函数对象类,令其执行if-then-else的操作:该类的调用运算符接受三个形参,
//它首先检查第一个形参,如果成功返回第二个形参的值,如果不成功返回第三个形参的值
struct ifelsethen
{
int operator(bool flag,int a,int b)
{
return flag? a:b;
}
}
14.35
14.36
/*
14.36 保存到vector
14.35 编写一个类似PrintString的类,令其从istream中读取一行输入,然后返回一个表示我们所读内容的string。如果读取失败,返回空string
*/
#include <iostream>
#include <string>
#include <vector>
class PrintStringLine
{
public:
std::string operator()(std::istream &in)
{
std::string line;
if (getline(in, line))
return line;
else
return std::string();
}
};
int main(int argc, char const *argv[])
{
PrintStringLine p;
//std::cout << "--" << p(std::cin) << "--" std::endl;
std::vector<std::string> v;
// v.push_back(p(std::cin));
// v.push_back(p(std::cin));
// v.push_back(p(std::cin));
// v.push_back(p(std::cin));
// v.push_back(p(std::cin));
for (std::string tmp; !(tmp = PrintStringLine()(std::cin)).empty();)
v.push_back(tmp);
for (auto ch : v)
std::cout << "~" << ch << "~" << std::endl;
while (1)
;
return 0;
}
14.37
/*
14.37 编写一个类令其检查两个值是否相等。使用该对象及标准库算法编写程序,令其替换某个序列中具有给定值的所有实例
*/
#include <vector>
#include <algorithm>
#include <iostream>
class Equal
{
private:
int data;
public:
Equal(int c) : data(c) {}
bool operator()(int a) { return a == data; }
};
int main(int argc, char const *argv[])
{
std::vector<int> v = {1, 2, 3, 4, 5, 6, 2, 3, 2, 1, 4, 6, 7, 8, 1, 2, 3, 1};
std::replace_if(v.begin(), v.end(), Equal(1), 9999);
// for (auto ch : v)
// std::cout << ch << ",";
// std::cout << std::endl;
std::for_each(v.begin(), v.end(), [](std::vector<int>::value_type c) { std::cout << c << ","; });
//std::for_each(v.begin(), v.end(), [](int c) { std::cout << c << ","; });
while (1)
{
/* code */
}
return 0;
}
14.38
14.39
/*
14.39 修改其报告1~9的单词有几个,10以上的有几个
14.38 编写一个类令其检查某个给定的string对象的长度是否与一个阀值相等。使用该对象编写程序,统计并报告在输入的文件中长度为1的单词有多少个、长度为2的单词有多少个。
*/
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
class StrLen
{
private:
int len;
bool cmp;
public:
StrLen(int l, bool cmp = false) : len(l), cmp(cmp) {}
bool operator()(const std::string &s)
{
if (cmp == false)
return s.size() == len;
else
return s.size() >= len;
}
};
int main(int argc, char const *argv[])
{
std::string path = "D:\\1.txt";
std::ifstream infile(path);
if (!infile)
{
std::cout << "err to open path" << path << std::endl;
while (1)
;
}
std::string s;
std::vector<std::string> v;
int len_1 = 0, len_2 = 0, len_10_big = 0, len_10_lit = 0;
StrLen l2(2);
StrLen l1(1);
StrLen l10(10, true);
while (infile >> s)
{
//v.push_back(std::move(s));
if (l1(s))
len_1++;
if (l2(s))
len_2++;
if (l10(s))
len_10_big++;
else
len_10_lit++;
}
std::cout << "len=1,count=" << len_1 << std::endl;
std::cout << "len=2,count=" << len_2 << std::endl;
std::cout << "len>=10,count=" << len_10_big << std::endl;
std::cout << "len<10>,count=" << len_10_lit << std::endl;
while (1)
;
return 0;
}
14.40
/*
14.40 重写10.3.2的P349 的biggies 函数,使用可调用类替换lambda
*/
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using std::cin;
using std::cout;
using std::endl;
using std::find_if;
using std::for_each;
using std::sort;
using std::stable_sort;
using std::string;
using std::vector;
class WordsABSizeCmp
{
public:
bool operator()(const string &a, const string &b)
{
return a.size() < b.size();
}
};
class WordsBigThan
{
private:
int default_size;
public:
WordsBigThan(int dsize) : default_size(dsize) {}
bool operator()(const string &a)
{
return a.size() >= default_size;
}
};
void elimdups(vector<string> &words)
{
sort(words.begin(), words.end());
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
}
string make_plural(size_t ctr, string const &word, string const &ending)
{
return (ctr > 1) ? word + ending : word;
}
class PrintString
{
private:
std::ostream &o;
public:
PrintString(std::ostream &o = std::cout) : o(o) {}
std::ostream &operator()(const string &s) { return o << s << ","; }
};
void biggies(vector<string> &words, vector<string>::size_type sz)
{
// 删除重复单词
elimdups(words);
// 按照长度排序单词
stable_sort(words.begin(), words.end(), WordsABSizeCmp());
// 找到第一个size大于某值的元素
auto wc = find_if(words.begin(), words.end(), WordsBigThan(sz));
// 计算size大于某值的数目
auto count = words.end() - wc;
cout << count << make_plural(count, "word", "s") << " of length " << sz << "or longer" << endl;
for_each(wc, words.end(), PrintString());
}
int main()
{
vector<string> vec{"fox", "jumps", "over", "quick", "red",
"red", "slow", "the", "turtle"};
biggies(vec, 4);
while (1)
{
/* code */
}
}
14.41
你认为C++11新标准为什么要增加lambda?对于你自己来说,什么情况下会使用lambda,什么情况下会使用类?
lambda 适合短小功能,不会反复复用
类,反复复用,功能多
14.42
(a)统计大于1024的值有多少个。
std::count_if(i.cbegin(),i.cend(),std::bind(std::greater<int>(),_1,1024));
(b)找到第一个不等于pooh的字符串。
std::find_if(i.cbegin(),i.cend(),std::bind(std::not_equal_to<string>(),_1,"pooh"));
(c)将所有的值乘以2.
std::transform(i.begin(),i.end(),i.begin(),bind(std::multiplies<int>(),_1,2));
14.43
/*
14.43:使用标准库函数对象判断一个给定的int值是否能被int容器中的所有元素整除
*/
#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>
using namespace std::placeholders;
bool IfDivVec(int a, std::vector<int> &v)
{
auto w = std::find_if(v.cbegin(), v.cend(), std::bind(std::modulus<int>(), _1, a));
return w == v.cend();
}
int main(int argc, char const *argv[])
{
int a = 3;
std::vector<int> v = {3, 6, 9, 18, 24};
std::cout << std::boolalpha << IfDivVec(a, v) << std::endl;
v.push_back(13);
std::cout << std::boolalpha << IfDivVec(a, v) << std::endl;
while (1)
;
return 0;
}
// auto data = {2, 3, 4, 5};
// int input;
// std::cin >> input;
// std::modulus<int> mod;
// auto predicator = [&](int i) { return 0 == mod(input, i); };
// auto is_divisible = std::any_of(data.begin(), data.end(), predicator);
// std::cout << (is_divisible ? "Yes!" : "No!") << std::endl;
14.45
14.45 编写类型转换运算符转换 Sales_data 到 string 和double
operator const string() { return bookNo; }
operator const double() { return GetAvg(); }
int main(int argc, char const *argv[])
{
Sales_data book1("ID1001", 10, 38);
cout << book1 << endl;
cout << static_cast<string>(book1) << endl;
cout << static_cast<double>(book1) << endl;
while (1)
;
return 0;
}
14.46
14.46 你认为应该定义上述两种类型转换吗 ? 是否要定义成 explicit?
不应该,转换的含义不明确,应该作为具体的成员函数
如果定义了,应该定义成 explicit 否则cout<<xxx 这类操作不知道怎么操作而且含义不精确
14.47
struct Integral
{
operator const int(); 返回值不能改变
operator int() const; 不会改变类对象的内容
};
14.48
14.49
TODO
14.50
// 可能用到哪些类类型的转换序列呢?说明初始化是否正确并解释原因
struct LongDouble {
LongDouble(double = 0.0);
operator double();
operator float();
};
LongDouble ldObj;
int ex1 = ldObj; // float 或者 double 二义性
float ex2 ldObj; // 调用operator float();
14.51
在调用calc的过程中,可能用到哪些类型转换序列呢?说明最佳可行函数是如何选拔出来的。
void calc(int);
void calc(LongDouble);
double dval;
calc(dval); //调用calc(int) 因为doube转int是标准类型转换
14.52
14.52 在下面的加法表达式中分别选用了哪个operator?
列出候选函数、可行函数及为每个可行函数的实参执行的类型转换
struct longDouble {
//用于演示的成员operator+; 在通常情况下+s是个非成员
longDouble operator+(const SmallInt&);
//其他成员与14.9.2节一致
};
longDouble operator+(longDouble&, double);
SmallInt si;
longDouble ld;
ld = si + ld; //没有转换的
ld = ld + si;
// 二义性
// 非成员 operator+ , >>> int转double
// 成员 operator+(const SmallInt&) 完全匹配的
14.53
14.53:假设我们已经定义了如第522页所示的SmallInt,判断下面的加法表达式是否合法。
如果合法,使用了哪个加法运算符?如果不合法,应该怎样修改代码才能使其合法?
SamllInt sl;
double d = s1 + 3.14;
// 1. 非成员函数 double转SamllInt 也就是构造函数 SamllInt(int) ===> double>int
// 2. SamllInt 转double 赋值
// 1. s1转int,
// 2. int 提升到 double
SmallInt s1;
double d = s1 + SmallInt(3.14);
StrBlob StrBlobPtr Strvec String
strblob.h
#ifndef __STR_BLOB_H__
#define __STR_BLOB_H__
#include <vector>
#include <memory>
#include <iostream>
#include <initializer_list>
#include <exception>
using std::cout;
using std::endl;
using std::initializer_list;
using std::make_shared;
using std::ostream;
using std::shared_ptr;
using std::string;
using std::vector;
class StrBlobPtr;
class ConstStrBlobPtr;
/**
* @brief vector<string>
*
*/
class StrBlob
{
using size_type = vector<string>::size_type;
friend std::ostream &operator<<(std::ostream &o, const StrBlob &s);
friend bool operator==(const StrBlob &, const StrBlob &);
friend bool operator!=(const StrBlob &, const StrBlob &);
friend bool operator<(const StrBlob &, const StrBlob &);
friend bool operator>(const StrBlob &, const StrBlob &);
friend bool operator<=(const StrBlob &, const StrBlob &);
friend bool operator>=(const StrBlob &, const StrBlob &);
friend class StrBlobPtr;
friend class ConstStrBlobPtr;
private:
shared_ptr<vector<string>>
data;
void check(size_type at, const string err_message) const;
public:
StrBlob() : data(make_shared<vector<string>>()) {}
StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}
// 拷贝构造,拷贝赋值,移动构造,移动赋值
StrBlob(const StrBlob &s) : data(make_shared<vector<string>>(*s.data)) {}
StrBlob &operator=(const StrBlob &s);
StrBlob(StrBlob &&s) noexcept : data(std::move(s.data)) {}
StrBlob &operator=(StrBlob &&s);
void push_back(const string &s) { data->push_back(s); }
void push_back(string &&s) { data->push_back(std::move(s)); }
void pop_back();
string &front();
string &back();
const string &front() const;
const string &back() const;
string &operator[](size_t at);
const string &operator[](size_t at) const;
// 迭代器相关的
StrBlobPtr begin(); // { return StrBlobPtr(*this); }
StrBlobPtr end(); //{ return StrBlobPtr(*this, data->size()); }
ConstStrBlobPtr cbegin(); // { return StrBlobPtr(*this); }
ConstStrBlobPtr cend(); //{ return StrBlobPtr(*this, data->size()); }
size_type size() const { return data->size(); }
};
inline StrBlob &StrBlob::operator=(const StrBlob &s)
{
data = make_shared<vector<string>>(*s.data);
return *this;
}
inline StrBlob &StrBlob::operator=(StrBlob &&s)
{
if (this != &s)
{
data = s.data;
s.data = nullptr;
}
return *this;
}
inline void StrBlob::check(size_type at, const string err_message) const
{
if (at >= data->size())
throw std::out_of_range(err_message);
}
inline void StrBlob::pop_back()
{
check(0, "try to pop empty vector!!!");
data->pop_back();
}
inline string &StrBlob::front()
{
check(0, "try to get front empty vector!!!");
return data->front();
}
inline string &StrBlob::back()
{
check(0, "try to get back empty vector!!!");
return data->back();
}
inline const string &StrBlob::front() const
{
check(0, "try to get front empty vector!!!");
return data->front();
}
inline const string &StrBlob::back() const
{
check(0, "try to get back empty vector!!!");
return data->back();
}
inline string &StrBlob::operator[](size_t at)
{
check(at, "out of range!!!");
return data->at(at);
}
inline const string &StrBlob::operator[](size_t at) const
{
check(at, "out of range!!!");
return data->at(at);
}
/**
* @brief vector<string> iterator
*
*/
class StrBlobPtr
{
friend bool operator==(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator!=(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator<(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator>(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator<=(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator>=(const StrBlobPtr &, const StrBlobPtr &);
private:
std::weak_ptr<vector<string>> wptr;
// convert weak_ptr to shared_ptr
shared_ptr<vector<string>> check(size_t at, string err_msg) const;
size_t curr;
public:
StrBlobPtr() : curr(0) {}
StrBlobPtr(StrBlob &s, size_t at = 0) : wptr(s.data), curr(at) {}
StrBlobPtr &operator++();
StrBlobPtr &operator--();
// 后置版本返回的是原来的值的拷贝,再++,所以不能返回引用
StrBlobPtr operator++(int);
StrBlobPtr operator--(int);
StrBlobPtr &operator+=(int);
StrBlobPtr &operator-=(int);
StrBlobPtr operator+(int) const;
StrBlobPtr operator-(int) const;
string &operator[](size_t);
const string &operator[](size_t) const;
string &operator*();
const string &operator*() const;
};
inline shared_ptr<vector<string>> StrBlobPtr::check(size_t at, string err_msg) const
{
auto ret = wptr.lock();
if (!ret)
throw std::runtime_error("No shared_ptr get!!!");
if (at > ret->size()) //because of at==ret->size when iterator arrive the end
throw std::out_of_range("out of range to check StrBlobPtr of" + err_msg);
return ret;
}
inline StrBlobPtr &StrBlobPtr::operator++()
{
++curr;
check(curr, "err to ++ ");
return *this;
}
inline StrBlobPtr &StrBlobPtr::operator--()
{
--curr;
check(curr, "err to -- ");
return *this;
}
inline StrBlobPtr StrBlobPtr::operator++(int)
{
StrBlobPtr ret = *this;
++*this;
return ret;
}
inline StrBlobPtr StrBlobPtr::operator--(int)
{
StrBlobPtr ret = *this;
--*this;
return ret;
}
inline StrBlobPtr &StrBlobPtr::operator+=(int offset)
{
curr += offset;
check(curr, "err to += ");
return *this;
}
inline StrBlobPtr &StrBlobPtr::operator-=(int offset)
{
curr -= offset;
check(curr, "err to -= ");
return *this;
}
inline StrBlobPtr StrBlobPtr::operator+(int offset) const
{
StrBlobPtr ret = *this;
ret += offset;
return *this;
}
inline StrBlobPtr StrBlobPtr::operator-(int offset) const
{
StrBlobPtr ret = *this;
ret -= offset;
return *this;
}
inline string &StrBlobPtr::operator[](size_t offset)
{
auto ret = check(offset, "Get [] err");
return (*ret)[offset];
}
inline const string &StrBlobPtr::operator[](size_t offset) const
{
auto ret = check(offset, "Get [] err");
return (*ret)[offset];
}
inline string &StrBlobPtr::operator*()
{
//auto ret = check(curr, "Get [] err");
//return ret->at(curr);
return (*this)[curr];
}
inline const string &StrBlobPtr::operator*() const
{
return (*this)[curr];
}
// 个人觉得应该是 非const的迭代器继承自const的迭代器 const_iterator
// --这里的const 是指不能通过该迭代器修改指向的内容
/**
* @brief vector<string> iterator
*
*/
class ConstStrBlobPtr
{
friend bool operator==(const ConstStrBlobPtr &, const ConstStrBlobPtr &);
friend bool operator!=(const ConstStrBlobPtr &, const ConstStrBlobPtr &);
friend bool operator<(const ConstStrBlobPtr &, const ConstStrBlobPtr &);
friend bool operator>(const ConstStrBlobPtr &, const ConstStrBlobPtr &);
friend bool operator<=(const ConstStrBlobPtr &, const ConstStrBlobPtr &);
friend bool operator>=(const ConstStrBlobPtr &, const ConstStrBlobPtr &);
private:
std::weak_ptr<vector<string>> wptr;
// convert weak_ptr to shared_ptr
shared_ptr<vector<string>> check(size_t at, string err_msg) const;
size_t curr;
public:
ConstStrBlobPtr() : curr(0) {}
ConstStrBlobPtr(const StrBlob &s, size_t at = 0) : wptr(s.data), curr(at) {}
ConstStrBlobPtr &operator++();
ConstStrBlobPtr &operator--();
// 后置版本返回的是原来的值的拷贝,再++,所以不能返回引用
ConstStrBlobPtr operator++(int);
ConstStrBlobPtr operator--(int);
ConstStrBlobPtr &operator+=(int);
ConstStrBlobPtr &operator-=(int);
ConstStrBlobPtr operator+(int) const;
ConstStrBlobPtr operator-(int) const;
//string &operator[](size_t); --这里的const 是指不能通过该迭代器修改指向的内容
const string &operator[](size_t) const;
//string &operator*();
const string &operator*() const;
};
inline shared_ptr<vector<string>> ConstStrBlobPtr::check(size_t at, string err_msg) const
{
auto ret = wptr.lock();
if (!ret)
throw std::runtime_error("No shared_ptr get!!!");
if (at > ret->size()) //because of at==ret->size when iterator arrive the end
throw std::out_of_range("out of range to check ConstStrBlobPtr of" + err_msg);
return ret;
}
inline ConstStrBlobPtr &ConstStrBlobPtr::operator++()
{
++curr;
check(curr, "err to ++ ");
return *this;
}
inline ConstStrBlobPtr &ConstStrBlobPtr::operator--()
{
--curr;
check(curr, "err to -- ");
return *this;
}
inline ConstStrBlobPtr ConstStrBlobPtr::operator++(int)
{
ConstStrBlobPtr ret = *this;
++*this;
return ret;
}
inline ConstStrBlobPtr ConstStrBlobPtr::operator--(int)
{
ConstStrBlobPtr ret = *this;
--*this;
return ret;
}
inline ConstStrBlobPtr &ConstStrBlobPtr::operator+=(int offset)
{
curr += offset;
check(curr, "err to += ");
return *this;
}
inline ConstStrBlobPtr &ConstStrBlobPtr::operator-=(int offset)
{
curr -= offset;
check(curr, "err to -= ");
return *this;
}
inline ConstStrBlobPtr ConstStrBlobPtr::operator+(int offset) const
{
ConstStrBlobPtr ret = *this;
ret += offset;
return *this;
}
inline ConstStrBlobPtr ConstStrBlobPtr::operator-(int offset) const
{
ConstStrBlobPtr ret = *this;
ret -= offset;
return *this;
}
// inline string &ConstStrBlobPtr::operator[](size_t offset)
// {
// auto ret = check(offset, "Get [] err");
// return (*ret)[offset];
// }
inline const string &ConstStrBlobPtr::operator[](size_t offset) const
{
auto ret = check(offset, "Get [] err");
return (*ret)[offset];
}
// inline string &ConstStrBlobPtr::operator*()
// {
// //auto ret = check(curr, "Get [] err");
// //return ret->at(curr);
// return (*this)[curr];
// }
inline const string &ConstStrBlobPtr::operator*() const
{
return (*this)[curr];
}
#endif // !__STR_BLOB_H__
strblob.cpp
#include "StrBlob.h"
//****************************************************************************
std::ostream &operator<<(std::ostream &o, const StrBlob &s)
{
for (size_t i = 0; i != s.size(); i++)
o << s[i] << ",";
return o;
}
bool operator==(const StrBlob &a, const StrBlob &b)
{
return *a.data == *b.data;
}
bool operator!=(const StrBlob &a, const StrBlob &b)
{
return !(a == b);
}
bool operator<(const StrBlob &a, const StrBlob &b)
{
return std::lexicographical_compare(a.data->begin(), a.data->end(),
b.data->begin(), b.data->end());
}
bool operator>(const StrBlob &a, const StrBlob &b)
{
return b < a;
}
bool operator<=(const StrBlob &a, const StrBlob &b)
{
return !(a > b);
}
bool operator>=(const StrBlob &a, const StrBlob &b)
{
return !(a < b);
}
StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{
return StrBlobPtr(*this, data->size());
}
ConstStrBlobPtr StrBlob::cbegin()
{
return ConstStrBlobPtr(*this);
}
ConstStrBlobPtr StrBlob::cend()
{
return ConstStrBlobPtr(*this, data->size());
}
//****************************************************************************
bool operator==(const StrBlobPtr &a, const StrBlobPtr &b)
{
return a.curr == b.curr;
}
bool operator!=(const StrBlobPtr &a, const StrBlobPtr &b)
{
return !(a == b);
}
bool operator<(const StrBlobPtr &a, const StrBlobPtr &b)
{
return (a.curr < b.curr);
}
bool operator>(const StrBlobPtr &a, const StrBlobPtr &b)
{
return (b < a);
}
bool operator<=(const StrBlobPtr &a, const StrBlobPtr &b)
{
return (b > a);
}
bool operator>=(const StrBlobPtr &a, const StrBlobPtr &b)
{
return (a < b);
}
//****************************************************************************
bool operator==(const ConstStrBlobPtr &a, const ConstStrBlobPtr &b)
{
return a.curr == b.curr;
}
bool operator!=(const ConstStrBlobPtr &a, const ConstStrBlobPtr &b)
{
return !(a == b);
}
bool operator<(const ConstStrBlobPtr &a, const ConstStrBlobPtr &b)
{
return (a.curr < b.curr);
}
bool operator>(const ConstStrBlobPtr &a, const ConstStrBlobPtr &b)
{
return (b < a);
}
bool operator<=(const ConstStrBlobPtr &a, const ConstStrBlobPtr &b)
{
return (b > a);
}
bool operator>=(const ConstStrBlobPtr &a, const ConstStrBlobPtr &b)
{
return (a < b);
}
//****************************************************************************
int main(int argc, char const *argv[])
{
try
{
StrBlob ls({"A", "B", "C"});
ls.push_back("D");
ls.pop_back();
std::cout << ls.front() << std::endl;
std::cout << ls.back() << std::endl;
std::cout << ls << std::endl;
StrBlob ls2({"A", "B", "C"});
std::cout << std::boolalpha << (ls == ls2) << std::endl;
ls2.push_back("D");
std::cout << std::boolalpha << (ls <= ls2) << std::endl;
//
ls.push_back("E");
std::cout << ls << std::endl;
std::cout << ls2 << std::endl;
std::cout << std::boolalpha << (ls2 > ls) << std::endl;
std::cout << "-------------------------------------" << std::endl;
std::cout << "-------------Test iterator-----------" << std::endl;
std::cout << "-------------------------------------" << std::endl;
for (auto i = ls.begin(); i != ls.end(); i++)
{
std::cout << *i << ",";
*i = "(" + *i + ")";
}
for (auto i = ls.begin(); i != ls.end(); i++)
std::cout << *i << ",";
for (auto i = ls.cbegin(); i != ls.cend(); i++)
{
std::cout << *i << ",";
//*i = "(" + *i + ")"; // does not match any in class
// inline string &ConstStrBlobPtr::operator[](size_t offset)
// 只有 const string
}
/* code */
}
catch (const std::exception &e)
{
std::cerr << e.what() << '\n';
}
while (1)
;
return 0;
}