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;
}

posted @ 2020-04-11 14:51  zongzi10010  阅读(146)  评论(0编辑  收藏  举报