c++primer 14.1-14.15
2019-06-12 本文已影响0人
青吟乐
14.1
当重载的运算符与内置运算符的参数,运行方式,中间过程不一样的时候两者有区别,但是在运算的优先级上,运算规则上面就一样。
14.2
#ifndef SALES_DATA_H_INCLUDED
#define SALES_DATA_H_INCLUDED
#include <string>
#include <iostream>
class Sales_data
{
//重载>>运算符
friend std::istream& operator>>(std::istream&, Sales_data&);
//重载<<运算符
friend std::ostream& operator<<(std::ostream&, const Sales_data&);
//重载+运算符
friend Sales_data operator+(const Sales_data&, const Sales_data&);
public:
Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(n*p) {}
Sales_data() : Sales_data("", 0, 0.0f) {}
Sales_data(const std::string &s) : Sales_data(s, 0, 0.0f) {}
Sales_data(std::istream &is);
//重载+=
Sales_data& operator+=(const Sales_data&);
std::string isbn() const { return bookNo; }
private:
inline double avg_price() const;
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
inline double Sales_data::avg_price() const
{
return units_sold ? revenue / units_sold : 0;
}
Sales_data::Sales_data(std::istream &is) : Sales_data()
{
is >> *this;
}
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
//重载>>运算符
std::istream& operator>>(std::istream &is, Sales_data &item)
{
double price = 0.0;
is >> item.bookNo >> item.units_sold >> price;
if (is)//若是输入没有问题,就计算收益,否则使用默认构造函数构造对象
item.revenue = price * item.units_sold;
else
item = Sales_data();
return is;//最后返回输入流
}
//重载<<运算符
std::ostream& operator<<(std::ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;//输出对象信息并且返回输出流
}
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;//拷贝lhs到sum
sum += rhs;//进行对象的加法运算
return sum;//返回对象的合成移动拷贝(右值)
}
#endif // SALES_DATA_H_INCLUDED
14.3
(a) 用的是判定运算符 不是string,也不是vector的==
(b)string的==
(c)vector的==
(d)我看不懂啥情况,前面多了一个双引号,要是没有那个双引号就是string的==
14.4
判断方法:默认是否可以直接对对象进行操作
(a)不需要重新定义即可使用,所以不需要是类成员
(b)%=改变了对象属性,所以要重新定义
(c)++也对对象的属性进行了改变,所以要自己定义
(d)是
(e)标准输出,不用是
(f)同e
(g)标准别断,不用是
(h)是
14.5
先来看看book类和其重载的运算符,重载了<<,>>,==,!=四个
#ifndef BOOK_H_INCLUDED
#define BOOK_H_INCLUDED
#include <iostream>
#include <string>
class Book
{
//重载>>
friend std::istream& operator>>(std::istream&, Book&);
//重载<<
friend std::ostream& operator<<(std::ostream&, const Book&);
//重载==
friend bool operator==(const Book&, const Book&);
//重载!=
friend bool operator!=(const Book&, const Book&);
public:
//使用默认的构造函数
Book() = default;
//四参数构造
Book(unsigned no, std::string name, std::string author, std::string pubdate) :no_(no), name_(name), author_(author), pubdate_(pubdate) {}
//输入构造
Book(std::istream &in) { in >> *this; }
private:
unsigned no_;
std::string name_;
std::string author_;
std::string pubdate_;
};
//重载>>
std::istream& operator>>(std::istream &in, Book &book)
{
//规范输入构造
in >> book.no_ >> book.name_ >> book.author_ >> book.pubdate_;
return in;
}
//重载<<
std::ostream& operator<<(std::ostream &out, const Book &book)
{
//规范输出
out << book.no_ << " " << book.name_ << " " << book.author_ << " " << book.pubdate_;
return out;
}
//重载==
bool operator==(const Book &lhs, const Book &rhs)
{
//判断no_
return lhs.no_ == rhs.no_;
}
//重载!=
bool operator!=(const Book &lhs, const Book &rhs)
{
//判断no_
return !(lhs == rhs);
}
#endif // BOOK_H_INCLUDED
再看看对四个重载运算符的测试
#include <iostream>
#include"Sales_data.h"
#include<vector>
#include"Book.h"
int main()
{ Book book1(12, "xxx", "leifeng", "1995");
Book book2(12, "xxx", "leifeng", "1995");
Book book3(11, "xxx", "leifeng", "1995");
if (book1 == book2)
std::cout << book1 << std::endl;
if (book2 == book3){
std::cout << book2 << std::endl;
}else{
std::cout << book1 << std::endl;
}
if(book2 != book3){
std::cout << book1 << std::endl;
}
Book book4;
std::cin>>book4;
std::cout << book4 << std::endl;
return 0;
}
使用正常
14.6
见14.2中对<<的重载,注意要对重载<<运算符声明成友元函数,要不然左侧对象
14.7
#ifndef STRING_H_INCLUDED
#define STRING_H_INCLUDED
#include <string>
#include <algorithm>
#include <memory>
#include <vector>
#include<iostream>
class String{
//重载<<
friend std::ostream& operator<<(std::ostream&, const String&);
public:
String():String(""){} //默认构造函数
String(const char *s){
auto s1 = const_cast<char*> (s); //const_cast的作用就是解const
for(;*s1;s1++){range_initializer(s, s1);} //计算字符长度
//申请内存
}
String(const String&);
String & operator=(const String& );
~String(){
free();
}
void free(){
if(elements){//若elements不为空
std::for_each(elements,first_free,[this](char &c){alloc.destroy(&c);});
alloc.deallocate(elements,first_free-elements);
}
}
//移动构造函数
String(String &&s) noexcept;
//移动构造运算符
String & operator=(String &&rhs) noexcept;
void range_initializer(const char*, const char*);
const char *c_str() const { return elements; }
private:
std::allocator<char> alloc; //用于申请内存
char *elements; //首指针
char *first_free; //尾后指针
std::pair<char*,char*> alloc_n_copy(const char *a,const char *b){
auto first_address = alloc.allocate(b-a); //返回申请内存的首指针
auto last_f_address = std::uninitialized_copy(a,b,first_address);//返回构造后的尾后指针
return {first_address,last_f_address}; //以pair的形式返回
}
};
void String::range_initializer(const char *first, const char *last)
{
auto newstr = alloc_n_copy(first, last);
elements = newstr.first;
first_free = newstr.second;
}
String::String(const String&s){
std::cout<<"拷贝构造函数"<<std::endl;
auto newStr = alloc_n_copy(s.elements,s.first_free);
elements = newStr.first;
first_free = newStr.second;
}
String& String::operator=(const String&a){
std::cout<<"拷贝赋值运算符"<<std::endl;
auto newc = alloc_n_copy(a.elements,a.first_free);
free();
elements = newc.first;
first_free = newc.second;
return *this;
}
//移动构造函数
String::String(String &&s) noexcept{
std::cout<<"移动构造函数"<<std::endl;
elements = s.elements;
first_free = s.first_free;
s.elements = s.first_free = nullptr;
}
//移动赋值运算符
String &String::operator=(String &&rhs) noexcept{
std::cout<<"移动赋值运算符"<<std::endl;
if(this!=&rhs){
free();
elements = rhs.elements;
first_free = rhs.first_free;
rhs.elements = rhs.first_free = nullptr;
}
return *this;
}
std::ostream& operator<<(std::ostream &os, const String &s)
{
char *c = const_cast<char*>(s.c_str());
while (*c)
os << *c++;
return os;
}
#endif // STRING_H_INCLUDED
测试一下
String s("xxxdsxx");
std::cout<<s<<std::endl;
可以
14.8
参考上面的14.5
14.9
注意使用友元函数
friend std::istream& operator>>(std::istream&, Sales_data&);
//实现>>运算符
std::istream& operator>>(std::istream &is, Sales_data &item)
{
double price = 0.0;
is >> item.bookNo >> item.units_sold >> price;
if (is)//若是输入流没有问题,就计算收益,否则使用默认构造函数构造对象
item.revenue = price * item.units_sold;
else
item = Sales_data();
return is;//最后返回输入流
}
14.10
a 输入没有问题
b 输入产生问题 24.95被转换成int类型 0-210-99999-9被修改成dounle类型(ps:用的codeblocks成功计算什么鬼,讲道理不应该是0吗)
14.11
输入数据有误,但是并不检查,什么都不会发生,最后就算结果0
14.12
//重载>>
std::istream& operator>>(std::istream &in, Book &book)
{
//规范输入构造
in >> book.no_ >> book.name_ >> book.author_ >> book.pubdate_;
if(!in){
//输入出现问题就自己处理一下参数
std::cout<<"输入有误,使用默认值"<<std::endl;
book.no_ = 0;
book.author_ = "null";
book.pubdate_ = "null";
}
return in;
}
14.13
无
14.14
operator+=返回对本对象进行修改,返回当前对象的指针但是operator=返回的一个副本,尽管有可能使用了移动构造函数,但是还是不如返回当前对象的指针高效
14.15
book类和方法
#ifndef BOOK_H_INCLUDED
#define BOOK_H_INCLUDED
#include <iostream>
#include <string>
class Book
{
//重载>>
friend std::istream& operator>>(std::istream&, Book&);
//重载<<
friend std::ostream& operator<<(std::ostream&, const Book&);
//重载==
friend bool operator==(const Book&, const Book&);
//重载!=
friend bool operator!=(const Book&, const Book&);
//正常重载这三个
friend bool operator<(const Book&, const Book&);
friend bool operator>(const Book&, const Book&);
friend Book operator+(const Book&, const Book&);
public:
//使用默认的构造函数
Book() = default;
//5参数构造
Book(unsigned no, std::string name, std::string author, std::string pubdate, unsigned number) :no_(no), name_(name), author_(author), pubdate_(pubdate), number_(number) {}
//输入构造
Book(std::istream &in) { in >> *this; }
Book& operator+=(const Book &rhs);
private:
unsigned no_;
std::string name_;
std::string author_;
std::string pubdate_;
unsigned number_;
};
//重载>>
std::istream& operator>>(std::istream &in, Book &book)
{
//规范输入构造
in >> book.no_ >> book.name_ >> book.author_ >> book.pubdate_;
if(!in){
//输入出现问题就自己处理一下参数
std::cout<<"输入有误,使用默认值"<<std::endl;
book.no_ = 0;
book.author_ = "null";
book.pubdate_ = "null";
}
return in;
}
//重载<<
std::ostream& operator<<(std::ostream &out, const Book &book)
{
//规范输出
out << book.no_ << " " << book.name_ << " " << book.author_ << " " << book.pubdate_;
return out;
}
//重载==
bool operator==(const Book &lhs, const Book &rhs)
{
//判断no_
return lhs.no_ == rhs.no_;
}
//重载!=
bool operator!=(const Book &lhs, const Book &rhs)
{
//判断no_
return !(lhs == rhs);
}
//重载<
bool operator<(const Book &lhs, const Book &rhs)
{
return lhs.no_ < rhs.no_;
}
//重载>,使用了<
bool operator>(const Book &lhs, const Book &rhs)
{
//翻过来用<
return rhs < lhs;
}
//重载+=
Book& Book::operator+=(const Book &rhs)
{
if (rhs == *this)
this->number_ += rhs.number_;
return *this;
}
//重载+
Book operator+(const Book &lhs, const Book &rhs)
{
Book book = lhs;
book += rhs;
return book;
}
#endif // BOOK_H_INCLUDED
测试数据
#include <iostream>
#include"Sales_data.h"
#include<vector>
#include"Book.h"
#include"String.h"
int main()
{
Book book1(12, "xxx", "leifeng", "1995",5);
std::cout << book1 << std::endl;
Book book2(12, "xxx", "leifeng", "1995",3);
Book book3(11, "xxx", "leifeng", "1995",4);
book1+=book2;
std::cout << book1 << std::endl;
bool b = book1<book2;
std::cout<<b<<std::endl;
bool a = book1>book3;
std::cout<<a<<std::endl;
return 0;
}