C++ Prime 第十四章 重载运算符与类型转换
2023-05-17~2023-05-18
14.1节练习
练习14.1:
相同点:重载后运算符的优先级、结合律不变
不同点:
1、对于重载后的运算符,必须是某个类的成员或者这个运算符的参数必须包含一个类类型
2、可以像调用普通函数一样调用重载后的运算符如 operator+(num1, num2)
3、重载后的运算符中的规则不再保留,如||、&&运算符的短路求值规则不在保留
练习14.2:
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<utility>
using namespace std;
class Sales_Date {
public:
friend Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2);
friend ostream& operator<<(ostream& out, Sales_Date& s);
friend istream& operator>>(istream& in, Sales_Date& s);
Sales_Date() = default;
Sales_Date(const string& no, unsigned sold, double reve) : bookNo(no), units_sold(sold),
revenue(reve) {};
Sales_Date& operator+=(Sales_Date& s)
{
revenue += s.revenue;
units_sold += s.units_sold;
return *this;
}
istream& operator+=(istream& in)
{
cout << "输入revenue:" << endl;
in >> revenue;
cout << "输入units_sold:" << endl;
in >> units_sold;
return in;
}
private:
string bookNo;
unsigned units_sold = 0.0;
int revenue = 0;
};
Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2)
{
Sales_Date s;
s.revenue = s1.revenue + s2.revenue;
s.units_sold = s1.units_sold + s2.units_sold;
return s;
}
ostream& operator<<(ostream& out, Sales_Date& s)
{
out << "revenue: " << s.revenue << endl;
out << "units_sold: " << s.units_sold << endl;
return out;
}
istream& operator>>(istream& in, Sales_Date& s)
{
cout << "输入revenue:" << endl;
in >> s.revenue;
cout << "输入units_sold:" << endl;
in >> s.units_sold;
return in;
}
void test()
{
Sales_Date s1("qwer", 10, 20);
Sales_Date s2("qwer", 20, 30);
Sales_Date s3 = s1 + s2;
cout << s3 << endl;
s3 += s1;
cout << s3 << endl;
cin >> s3;
cout << s3 << endl;
}
int main()
{
test();
system("pause");
return 0;
}
练习14.3:
(a):string版本
(b):string版本
(c):vector版本
(d):string版本\
练习14.4:
对于运算符能够任意转换一端的对象的应该作为非成员运算符
非成员运算符:(a)、(b)、(f)、(g)
成员运算符:(b)、(c)、(d)、(e)
练习14.5:
略(基本和练习14.2中的Sales_data一样)
14.2.1节练习
练习14.6:
见练习14.5
练习14.7:
class String
{ friend ostream& operator<<(ostream& out, String& s);
};
ostream& operator<<(ostream& out, String& s)
{
for (auto iter = s.begin(); iter != s.end(); ++iter)
{
out << *iter << endl;;
}
return out;
}
练习14.8:
略
14.2.2节练习
练习14.9:
见练习14.5
练习14.10:
(a)正常输入
(b)输入失败(第三个次输入是double类型,但是输入了一个非double类型的数据),会返回一个初始化的Sales_data对象
练习14.11:
没有检查输入是否成功,如果输入不规范的数据会导致程序退出
练习14.12:
class Book
{
public:
int No;
};
istream& operator>>(istream& in, Book& b)
{
in >> b.No;
if (in)
{
return in;
}
else
{
cout << "输入错误" << endl;
return in;
}
}
14.3节练习
练习14.13:
一些复合赋值运算符、定义略
练习14.14:
+= 不需要构造临时对象
练习14.15:
略
14.3.1节练习
练习14.16:
全都类似Sales_data
bool operator==(const Sales_Date& s1, const Sales_Date& s2)
{
return s1.bookNo == s2.bookNo && s1.revenue == s2.revenue &&
s1.units_sold == s1.units_sold;
}
bool operator!=(const Sales_Date& s1, const Sales_Date& s2)
{
return !(s1 == s2);
}
练习14.17:
略
14.3.2节练习
练习14.18:
#include<iostream>
#include<vector>
#include<memory>
#include<set>
#include<map>
#include<string>
#include<algorithm>
#include<utility>
#include<initializer_list>
#include<fstream>
#include<sstream>
using namespace std;
class String
{
public:
friend ostream& operator<<(ostream& out, String& s);
friend bool operator==(String& s1, String& s2);
friend bool operator!=(String& s1, String& s2);
friend bool operator<(String& s1, String& s2);
friend bool operator<=(String& s1, String& s2);
friend bool operator>(String& s1, String& s2);
friend bool operator>=(String& s1, String& s2);
String() : elements(nullptr), first_free(nullptr), cap(nullptr) {};
//2、有参构造函数:
//2.1、参数是const char[]对象
String(const char* p)
{
auto new_data = chk_n_copy(p);
elements = new_data.first;
first_free = cap = new_data.second;
}
//2.2、参数是initializer_list<char>&
String(const initializer_list<char>& c)
{
auto new_data = chk_n_copy(c.begin(), c.end());
elements = new_data.first;
first_free = cap = new_data.second;
}
// 添加一个移动构造函数
String(String&& s) noexcept :elements(s.elements), first_free(s.first_free),
cap(s.cap)
{
cout << "移动构造函数" << endl;
s.elements = s.first_free = s.cap = nullptr;
}
//3、拷贝构造函数
String(const String& s)
{
cout << "拷贝构造函数" << endl;
auto new_data = chk_n_copy(s.cbegin(), s.cend());
elements = new_data.first;
first_free = cap = new_data.second;
}
//添加一个移动赋值运算符
String& operator=(String&& s)
{
if (this != &s)
{
cout << "移动赋值运算符" << endl;
free();
elements = s.elements;
first_free = s.first_free;
cap = s.cap;
s.elements = s.first_free = s.cap = nullptr;
}
return *this;
}
//4、赋值运算符
String& operator=(const String& s)
{
cout << "赋值运算符" << endl;
auto new_data = chk_n_copy(s.cbegin(), s.cend());
free();
elements = new_data.first;
first_free = cap = new_data.second;
return *this;
}
//5、析构函数:
~String() { free(); };
char* elements;
char* first_free;
char* cap;
//6、size函数
size_t size() { return first_free - elements; };
//7、capacity函数
size_t capacity() { return cap - elements; };
//8、resize函数
void resize(size_t num, char c = '\0')
{
char* end_iter = nullptr;
if (size() > num)
{
end_iter = first_free - (size() - num);
for (auto p = first_free; p != end_iter;)
{
alloc.destroy(--p);
}
}
else if (num > size() && num <= capacity())
{
end_iter = first_free + (num - size());
for (auto p = first_free; p != end_iter;)
{
alloc.construct(p++, c);
}
}
else if (num > size() && num > capacity())
{
reallocate_memory(num);
end_iter = first_free + (num - size());
for (auto p = first_free; p != end_iter;)
{
alloc.construct(p++, c);
}
}
first_free = end_iter ? end_iter : first_free;
}
//9、reserve
void reserve(size_t num) { if (num > capacity()) reallocate_memory(num); };
//10、push_back函数
void push_back(char c)
{
chk_n_alloc();
alloc.construct(first_free++, c);
}
//11、clear函数
void clear()
{
for_each(elements, first_free,
[](const char& p) { alloc.destroy(&p);}
);
first_free = elements;
}
char* begin() const { return elements; };
char* end() const { return first_free; };
const char* cbegin() const { return elements; };
const char* cend() const { return first_free; };
void test();
private:
static allocator<char> alloc;
void free();
pair<char*, char*> chk_n_copy(const char* p);
pair<char*, char*> chk_n_copy(const char* b, const char* e);
void reallocate_memory(size_t num);
void chk_n_alloc();
};
// 静态对象类外初始化
allocator<char> String::alloc;
//14.1、free函数
inline void String::free()
{
if (elements)
{
for_each(elements, first_free,
[this](const char& c) { alloc.destroy(&c); }
);
alloc.deallocate(elements, cap - elements);
elements = nullptr;
first_free = nullptr;
cap = nullptr;
}
}
//14.2、chk_n_copy(const char* p))函数
inline pair<char*, char*> String::chk_n_copy(const char* p)
{
auto elem = p;
int str_length = 0;
while (*elem != '\0')
{
++str_length;
++elem;
}
auto new_data = alloc.allocate(str_length);
return { new_data, uninitialized_copy(p, elem, new_data) };
}
//14.2、chk_n_copy(const char* p))函数,重载版本
inline pair<char*, char*> String::chk_n_copy(const char* b, const char* e)
{
auto new_data = alloc.allocate(e - b);
return { new_data, uninitialized_copy(b, e, new_data) };
}
//14.3、reallocate_memory(num)函数
inline void String::reallocate_memory(size_t num)
{
auto new_data = alloc.allocate(num);
auto dest = new_data;
auto elem = elements;
for (size_t i = 0; i < size(); ++i)
{
alloc.construct(dest++, std::move(*elem++));
}
free();
elements = new_data;
first_free = dest;
cap = elements + num;
}
//14.4、chk_n_alloc函数
inline void String::chk_n_alloc()
{
if (size() == capacity())
{
size_t new_capacity = size() ? size() * 2 : 1;
reallocate_memory(new_capacity);
}
}
ostream& operator<<(ostream& out, String& s)
{
for (auto iter = s.begin(); iter != s.end(); ++iter)
{
out << *iter << endl;;
}
return out;
}
bool operator==(String& s1, String& s2)
{
if (s1.size() != s2.size())
{
return false;
}
auto s1_iter = s1.begin();
auto s2_iter = s2.begin();
for (int i = 0; i < s1.size(); ++i)
{
if (*s1_iter != *s2_iter)
{
return false;
}
++s1_iter;
++s2_iter;
}
return true;
}
bool operator!=(String& s1, String& s2)
{
return !(s1 == s2);
}
bool operator<(String& s1, String& s2)
{
auto s1_begin = s1.begin();
auto s2_begin = s2.begin();
if (s2.size() < s1.size())
{
auto same_flag = true;
for (int i = 0; i < s2.size(); ++i)
{
if (*s1_begin > *s2_begin)
{
return false;
}
++s1_begin;
++s2_begin;
}// 循环完只能说明s2并不小于s1,s2有可能等于s1
// 再次循环测试s2是否==s1
for (int i = 0; i < s2.size(); ++i)
{
--s1_begin;
--s2_begin;
if (*s1_begin != *s2_begin)
{
same_flag = false;
}
}
if (same_flag)
{
return false;
}
return true;
}
else
{
if (s2.size() == s1.size())
{
if (s1 == s2)
{
return false;
}
}
for (int i = 0; i < s1.size(); ++i)
{
if (*s1_begin > *s2_begin)
{
return false;
}
++s1_begin;
++s2_begin;
}
return true;
}
}
bool operator<=(String& s1, String& s2)
{
if (s1 == s2)
{
return true;
}
if (s1 < s2)
{
return true;
}
return false;
}
bool operator>(String& s1, String& s2)
{
return s2 < s1;
}
bool operator>=(String& s1, String& s2)
{
if (s1 == s2)
{
return true;
}
if (s1 > s2)
{
return true;
}
return false;
}
void String::test()
{
chk_n_alloc();
}
int main()
{
String s1("aaadaaaaaaaaa");
String s2("aaadaaaaaaaaaa");
cout << (s1 >= s2) << endl;
string s3("aaadaaaaaaaaa");
string s4("aaadaaaaaaaaaa");
cout << (s3 >= s4) << endl;
system("pause");
return 0;
}
练习14.19:
略
14.4节练习
练习14.20:
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<utility>
using namespace std;
class Sales_Date {
public:
friend Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2);
friend ostream& operator<<(ostream& out, Sales_Date& s);
friend istream& operator>>(istream& in, Sales_Date& s);
friend bool operator==(const Sales_Date& s1, const Sales_Date& s2);
friend bool operator!=(const Sales_Date& s1, const Sales_Date& s2);
Sales_Date() = default;
Sales_Date(const string& no, unsigned sold, double reve) : bookNo(no), units_sold(sold),
revenue(reve) {};
Sales_Date& operator+=(Sales_Date& s)
{
revenue += s.revenue;
units_sold += s.units_sold;
return *this;
}
Sales_Date& operator+=(Sales_Date& s);
istream& operator<<(istream& in)
{
cout << "输入revenue:" << endl;
in >> revenue;
cout << "输入units_sold:" << endl;
in >> units_sold;
return in;
}
private:
string bookNo;
unsigned units_sold = 0.0;
int revenue = 0;
};
Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2)
{
Sales_Date s;
s.revenue = s1.revenue + s2.revenue;
s.units_sold = s1.units_sold + s2.units_sold;
return s;
}
ostream& operator<<(ostream& out, Sales_Date& s)
{
out << "revenue: " << s.revenue << endl;
out << "units_sold: " << s.units_sold << endl;
return out;
}
istream& operator>>(istream& in, Sales_Date& s)
{
int s1;
in >> s1;
if (!in)
{
cout << 12 << endl;
}
cout << "输入revenue:" << endl;
in >> s.revenue;
cout << "输入units_sold:" << endl;
in >> s.units_sold;
return in;
}
bool operator==(const Sales_Date& s1, const Sales_Date& s2)
{
return s1.bookNo == s2.bookNo && s1.revenue == s2.revenue &&
s1.units_sold == s1.units_sold;
}
bool operator!=(const Sales_Date& s1, const Sales_Date& s2)
{
return !(s1 == s2);
}
void test()
{
//Sales_Date s1("qwer", 10, 20);
//Sales_Date s2("qwer", 20, 30);
//Sales_Date s3 = s1 + s2;
//cout << s3 << endl;
//s3 += s1;
//cout << s3 << endl;
//cin >> s3;
//cout << s3 << endl;
}
int main()
{
system("pause");
return 0;
}
练习14.21:
Sales_Date& operator+(Sales_Date& s1, Sales_Date& s2)
{
Sales_Date s;
s.revenue = s1.revenue + s2.revenue;
s.units_sold = s1.units_sold + s2.units_sold;
return s;
}
Sales_Date& Sales_Date::operator+=(Sales_Date& s)
{
*this = *this + s;
return *this;
}
练习14.22:
Sales_Date& operator=(const string bn)
{
bookNo = bn;
return *this;
}
练习14.23:
StrVec& StrVec::operator=(initializer_list<string>& s)
{
auto new_data = chk_n_copy(s.begin(), s.end());
free();
elements = new_data.first;
first_free = cap = new_data.second;
return *this;
}
练习14.24~14.25:
略
14.5节练习
练习14.26:
char& operator[](int i)
{
if (i < size())
{
return elements[i];
}
}
const char& operator[](int i) const
{
if (i < size())
{
return elements[i];
}
}
14.6节练习
练习14.27:
StrBlobPtr& operator++()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
StrBlobPtr& operator--()
{
check(curr, "increment past end of StrBlobPtr");
--curr;
return *this;
}
StrBlobPtr operator++(int)
{
auto ret = *this;
++* this;
return ret;
}
StrBlobPtr operator--(int)
{
auto ret = *this;
--* this;
return ret;
}
练习14.28:
StrBlobPtr operator+(int num)
{
auto ret = *this;
this->curr += num;
return ret;
}
StrBlobPtr operator-(int num)
{
auto ret = *this;
this->curr -= num;
return ret;
}
练习14.29:
需要修改对象本身的属性所以不用const
14.7节练习
练习14.30:
string& operator*() const
{
auto p = check(curr, "dereference......");
return (*p)[curr];
}
string* operator->() const
{
return &operator*();
}
练习14.31:
StrBolbPtr的成员分别是智能指针和内置数据类型,所以使用合成的析构函数、赋值运算符、构造函数即可
练习14.32:
class StrBlobPtrPtr
{
public:
StrBlobPtrPtr(StrBlobPtr& s) : ptr(&s) {};
StrBlobPtr* operator->()
{
return &(*ptr);
}
private:
StrBlobPtr* ptr;
};
14.8节练习
练习14.33:
至少一个(隐式接受一个this指针)
练习14.34:
class Test
{
public:
int operator()(int a, int b, int c)
{
if (a == 0)
{
return b;
}
else
{
return c;
}
}
};
int main()
{
Test t;
cout << t(1, 2, 3) << endl;;
system("pause");
return 0;
}
练习14.35:
class PrintString
{
public:
const string operator()(istream& in)
{
string s;
in >> s;
if (in)
{
return s;
}
return "";
}
};
int main()
{
PrintString t;
cout << t(cin) << endl;;
system("pause");
return 0;
}
练习14.36:
class PrintString
{
public:
void operator()(istream& in)
{
string s;
vector<string> vec;
while (in >> s)
{
vec.push_back(s);
}
for (auto temp : vec)
{
cout << temp << endl;
}
}
};
int main()
{
PrintString t;
t(cin);
system("pause");
return 0;
}
练习14.37:
class isSame
{
public:
bool operator()(int a)
{
return a == 2;
}
};
int main()
{
vector<int> vec = { 2, 2, 2, 3, 3, 3, 2, 2 };
replace_if(vec.begin(), vec.end(), isSame(), 20);
for (auto temp : vec)
{
cout << temp << endl;
}
system("pause");
return 0;
}
14.8.1节练习
练习14.38:
class StringLength
{
public:
StringLength(int sz) : limit(sz) {};
bool operator()(string s)
{
return s.size() == limit;
}
private:
int limit;
};
int main()
{
vector<string> vec = { "aaaa", "aaaa", "asadaaa", "aaaa", "a", "aa" };
for (int i = 1; i < 11; ++i)
{
cout << "长度=" << i << "有:" <<
count_if(vec.begin(), vec.end(), StringLength(i)) << endl;
}
system("pause");
return 0;
}
练习14.39:
class StringLength
{
public:
StringLength(int sz1, int sz2=100) : limit1(sz1), limit2(sz2) {};
bool operator()(string s)
{
return (s.size() > limit1) && (s.size() < limit2);
}
private:
int limit1;
int limit2;
};
int main()
{
vector<string> vec = { "aaaa", "aaaa", "asadaaa", "aaaa", "aa", "aa" };
cout << "长度1~9有:" <<
count_if(vec.begin(), vec.end(), StringLength(1, 9)) << endl;
cout << "长度大于10有:" <<
count_if(vec.begin(), vec.end(), StringLength(10)) << endl;
system("pause");
return 0;
}
练习14.40:
class Stable_sort
{
public:
bool operator()(const string& a, const string& b)
{
return a.size() < b.size();
}
};
void biggies(vector<string>& words, vector<string>::size_type sz)
{
//elimDups(words);
stable_sort(words.begin(), words.end(), Stable_sort());
//......基本如Stable_sort一致
}
练习14.41:
通过lambda函数来提供更简单、方便的匿名函数的使用。
对于简单的、一次性的的逻辑函数使用lambda函数。对于需要将函数作为参数传递的也可以使用lambda,对于需要捕获上下文中变量进行功能编写的函数也可以使用lambda免去定义变量的繁琐。
对于复杂需要重复使用的函数对象可以使用类来实现,通过增加类的成员来完成复杂的功能
14.8.2节练习
练习14.42:
(a)
vector<int> vec = { 100, 10000, 1000 };
cout << count_if(vec.begin(), vec.end(), bind(greater<int>(), placeholders::_1, 1024));
(b)
vector<string> vec = { "pooh", "pooh1", "1000" };
auto ret = find_if(vec.begin(), vec.end(), bind(not_equal_to<string>(), placeholders::_1, "pooh"));
cout << *ret << endl;
(c)
vector<int> vec = { 100, 200, 300 };
auto ret = transform(vec.begin(), vec.end(), vec.begin(),
bind(multiplies<int>(), placeholders::_1, 2));
for (auto temp : vec)
{
cout << temp << endl;
}
练习14.43:
使用标准库函数允许的代码结果不正确
vector<int> vec = { 100, 200, 300 };
bool ret = all_of(vec.begin(), vec.end(), bind(modulus<int>(), placeholders::_1, 300)) == 0;
cout << ret << endl;
使用lambda正确
vector<int> vec = { 100, 200, 300 };
bool ret = all_of(vec.begin(), vec.end(), [](int num) { return num % 300 == 0; });
cout << ret << endl;
练习14.8.3
练习14.44:
int add(int a, int b)
{
return a + b;
}
class Multiplies
{
public:
int operator()(int a, int b)
{
return a * b;
}
};
int main()
{
map<string, function<int(int, int)>> binops;
binops.insert({ "+", add });
binops.insert({ "-", minus<int>()});
binops.insert({ "*", Multiplies() });
binops.insert({ "/", [](int a, int b) {return a / b; } });
cout << binops["+"](1, 2) << endl;
cout << binops["-"](1, 2) << endl;
cout << binops["*"](1, 2) << endl;
cout << binops["/"](1, 2) << endl;
system("pause");
return 0;
}
14.9.1节练习
练习14.45:
返回对应类型的值(string、doule)
练习14.46:
不应该,我们并不需要将string或者其他类型的数据转化成Sales_data
练习14.47:
operator const int()限制返回值不能被修改
operator int() const 函数体的定义内不能对转化对象进行修改
练习14.48:
不需要
练习14.49:
class Book
{
public:
Book(int tn) : thinkness(tn) {};
operator bool()
{
if (thinkness)
{
return thinkness;
}
else
{
return 0;
}
}
private:
int thinkness;
};
int main()
{
Book b(10);
if (b)
{
cout << b << endl;
}
system("pause");
return 0;
}
14.9.2节练习
练习14.50:
int ex1初始化失败,operator double()返回double,operator float()返回float,这两者都可以转化成int,产生二义性。 int ex2使用operator float()返回float为ex2赋值
练习14.51:
调用calc(int),LongDouble是自定义数据类型,int是内置类型,优先将double类型的数据转化成int而不是转化成自定义数据类型LongDouble
14.9.3节练习
练习14.52:
ld = si + ld;SmallInt和LongDouble两者没有相互转化的类型转化函数和符合参数的重载运算符,所以只能将is和ld转化成内置数据类型使用内置数据类型相加,si转化成int与ld相加,ld转化成int时产生二义性(operator double()返回double,operator float()返回float,这两者都可以转化成int),
ld = ld + si;符合LongDouble的重载的成员运算符+
练习14.53:
不合法,double d = s1 + 3.14;符合两个函数的参数要求会产生二义性,将s1显示的转化成内置数据类型即可使用static_cast(s1)
勇敢和愚蠢只有一剑之差