c++ primer中文版第五版作业第十四章

见仓库

文章目录

      • 14.1
      • 14.2
      • 14.3
      • 14.4
      • 14.5
      • 14.6
      • 14.7
      • 14.8
      • 14.9
      • 14.10
      • 14.11
      • 14.12
      • 14.13
      • 14.14
      • 14.15
      • 14.16
      • 14.17
      • 14.18
      • 14.19
      • 14.20
      • 14.21
      • 14.22
      • 14.23
      • 14.24
      • 14.25
      • 14.26
      • 14.27
      • 14.28
      • 14.29
      • 14.30
      • 14.31
      • 14.32
      • 14.33
      • 14.34
      • 14.35
      • 14.36
      • 14.37
      • 14.38
      • 14.39
      • 14-40
      • 14.41
      • 14.42
      • 14.43
      • 14.44
      • 14.45
      • 14.46
      • 14.47
      • 14.48
      • 14.49
      • 14.50
      • 14.51
      • 14.52
      • 14.53

14.1

  • 不同点:重载运算符至少有一个类类型的运算对象。重载运算符实际上是具有特殊名字的函数,所以它无法保留内置运算符的求值顺序或短路求值属性。重载运算符有可能被定义成与内置运算符不一样的含义。
  • 相同点:重载运算符与内置运算符在运算对象数量、优先级和结合律等方面保持一致。

14.2

Sales_data.h

#include <iostream>
#include <string>
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:std::string isbn() const {return bookNo;}Sales_data()=default;Sales_data(const std::string &s):bookNo(s) {}Sales_data(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(n*p) {}Sales_data & operator+=(const Sales_data &);private:std::string bookNo;unsigned units_sold=0;double revenue=0.0;double avg_price() const;
};
std::istream & operator>>(std::istream &,Sales_data &);
std::ostream & operator<<(std::ostream &,const Sales_data &);
Sales_data operator+(const Sales_data &,const Sales_data &);

Sales_data.cpp

#include "Sales_data.h"
inline double Sales_data::avg_price() const
{if(units_sold)return revenue/units_sold;elsereturn 0;
}
std::istream & operator>>(std::istream &is,Sales_data &src)
{double price=0.0;is>>src.bookNo>>src.units_sold>>price;if(is)src.revenue=src.units_sold*price;elsesrc=Sales_data();return is;
}
std::ostream & operator<<(std::ostream &os,const Sales_data &src)
{os<<src.isbn()<<" "<<src.units_sold<<" "<<src.revenue<<" "<<src.avg_price();return os;
}
Sales_data & Sales_data::operator+=(const Sales_data & rhs)
{units_sold+=rhs.units_sold;revenue+=rhs.revenue;return *this;
}
Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs)
{Sales_data tmp;tmp=lhs;tmp+=rhs;return tmp;
}

14.3

  1. "cobble"=="stone"比较的两个数据都是const char *类型,使用了内置运算符;
  2. svec1[0]==svec2[0]比较的两个数据都是string &,使用了string类型重载的==;
  3. svec1==svec2比较的两个数据都是vector,使用了vector类型重载的==;
  4. svec1[0]=="stone"中"stone"将会转换为string,使用了string类型重载的==;

14.4

% \% %非成员函数
% = \%= %=成员函数
+ + ++ ++成员函数
− > -> >成员函数
< < << <<非成员函数
& & \&\& &&非成员函数
= = == ==非成员函数
( ) () ()成员函数

14.5

 练习7.40中,编写的是Employee的框架,建议为其重载输入、输出运算符。

14.6

见14.2

14.7

String.h

#ifndef _sTRING_H
#define _sTRING_H
#include <iostream>
#include <utility>
class String
{friend std::istream & operator>>(std::istream &in,String &str);friend std::ostream & operator<<(std::ostream &out,const String &str);public:String():head(nullptr),tail(nullptr),cap(nullptr) {}String(const char *);String(const String &);String(String &&str) noexcept :head(str.head),tail(str.tail),cap(str.cap) {str.head=str.tail=str.cap=nullptr;std::cout<<"This is move constructor."<<std::endl;}String & operator=(const String &);String & operator=(String &&);String operator+(const String &);~String() {free();}size_t size() const {return tail-head;}size_t capacity() const {return cap-head;}bool empty() const {return (head==tail)?true:false;}char * begin() const {return head;}char * end() const {return tail;}private:char *head;char *tail;char *cap;static std::allocator<char> alloc;void free();std::pair<char *,char *> alloc_n_copy(const char *,const char *);void chk_n_alloc(size_t n) {if(n+size()>capacity()) reallocate(n);}void reallocate(size_t n);
};
std::istream & operator>>(std::istream &in,String &str);
std::ostream & operator<<(std::ostream &out,const String &str);
#endif

String.cpp

#include <memory>
#include <algorithm>
#include <cstring>
#include <string>
#include "String.h"String::String(const char *str)
{size_t n=strlen(str);std::pair<char *,char *> newdata=alloc_n_copy(str,str+n);head=newdata.first;tail=cap=newdata.second;
}
String::String(const String &s)
{std::cout<<"This is copy constructor."<<std::endl;std::pair<char *,char *> newdata=alloc_n_copy(s.begin(),s.end());head=newdata.first;tail=cap=newdata.second;
}
String & String::operator=(const String &rhs)
{std::cout<<"This is copy assignment operator."<<std::endl;std::pair<char *,char *> newdata=alloc_n_copy(rhs.begin(),rhs.end());free();head=newdata.first;tail=cap=newdata.second;return *this;
}
String & String::operator=(String &&rhs)
{std::cout<<"This is move assignment operator."<<std::endl;if(this!=&rhs){free();head=rhs.head;tail=rhs.tail;cap=rhs.cap;rhs.head=rhs.tail=rhs.cap=nullptr;}return *this;
}
String String::operator+(const String &rhs)
{String tmp(*this);size_t n=rhs.size();tmp.chk_n_alloc(n);char *dest=tmp.tail;char *src=rhs.begin();for(size_t i=0;i!=6;++i)alloc.construct(dest++,*src++);tmp.tail=dest;return tmp;
}std::allocator<char> String::alloc;
void String::free()
{if(head){std::for_each(begin(),end(),[](char &c) {alloc.destroy(&c);});alloc.deallocate(head,cap-head);}
}
std::pair<char *,char *> String::alloc_n_copy(const char *b,const char *e)
{char *newdata=alloc.allocate(e-b);return {newdata,std::uninitialized_copy(b,e,newdata)};
}
void String::reallocate(size_t n)
{size_t newcap=(size()>n?size()*2:n*2);char *newdata=alloc.allocate(newcap);char *dest=newdata;char *src=head;for(size_t i=0;i!=size();++i)alloc.construct(dest++,std::move(*src++));free();head=newdata;tail=dest;cap=head+newcap;
}
std::istream & operator>>(std::istream &in,String &str)
{std::string tmp;in>>tmp;String Stmp(tmp.c_str());str=Stmp;return in;
}
std::ostream & operator<<(std::ostream &out,const String &str)
{std::for_each(str.begin(),str.end(),[&out](const char &c)->void {out<<c;});return out;
}

14.8

Employee.h

#ifndef _EMPLOYEE_H
#define _EMPLOYEE_H
#include <iostream>
class Employee
{friend std::ostream & operator<<(std::ostream &,const Employee &);friend std::istream & operator>>(std::istream &,Employee &);public:Employee()=default;Employee(std::string s):name(s){}Employee(std::string s,unsigned int i,double j,unsigned int k):name(s),Age(i),salary(j),Phone_Number(k){}private:std::string name;unsigned int Age=0;double salary=0;unsigned int Phone_Number=0;
};
std::ostream & operator<<(std::ostream &,const Employee &);
std::istream & operator>>(std::istream &,Employee &);
#endif

Employee.cpp

#include "Employee.h"
std::ostream & operator<<(std::ostream &os,const Employee &src)
{os<<src.name<<" "<<src.Age<<" "<<src.salary<<" "<<src.Phone_Number;return os;
}
std::istream & operator>>(std::istream &is,Employee &src)
{is>>src.name>>src.Age>>src.salary>>src.Phone_Number;if(!is)src=Employee();return is;
}

14.9

见14.2

14.10

  1. 输入正确,可以得到输入中的正确数据
  2. 输入错误,可以得到默认值的Sales_data对象

14.11

 此重载的输入运算符没有判断输入失败的情况,在输入失败时,bookNo、units_sold、price都可能是非法数据,由此得到非法的Sales_data对象。这个输入运算符如果仍然给定上个练习的输入,那么第一个输入仍将得到合法的对象,而第二个输入会得到非法的对象。

14.12

见14.8

14.13

 对于Sales_data类,其它的算术运算符没有明确的意义

14.14

 因为operator+本来就是返回的值,所以使用operator+=并不会有性能上的损失,同时具有较高的可读性.

14.15

Employee类的信息是雇员的名字、年纪、收入、电话,算术运算符对其没有明确的意义,故不应该含有其他算术运算符。

14.16

StrBlob.h

#ifndef STRBLOB_H
#define STRBLOB_H
#include <memory>
#include <vector>
#include <string>
#include <initializer_list>
#include <stdexcept>
class StrBlobPtr;
class StrBlob
{
friend class StrBlobPtr;
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 &);
public:typedef std::vector<std::string>::size_type size_type;StrBlob();StrBlob(std::initializer_list<std::string> il);StrBlob(const StrBlob &);StrBlob & operator=(const StrBlob &);std::string & operator[](std::size_t i) {return data->at(i);}const std::string & operator[](std::size_t i) const {return data->at(i);}size_type size() const {return data->size();}bool empty() const {return data->empty();}void push_back(const std::string &t){data->push_back(t);}void push_back(std::string &&t){data->push_back(std::move(t));}void pop_back();std::string &front();std::string &back();const std::string &front() const;const std::string &back() const;StrBlobPtr begin();StrBlobPtr begin() const;StrBlobPtr end();StrBlobPtr end() const;
private:std::shared_ptr<std::vector<std::string>> data;void check(size_type i,const std::string &msg) const;
};
bool operator==(const StrBlob &,const StrBlob &);
bool operator!=(const StrBlob &,const StrBlob &);
bool operator<(const StrBlob &,const StrBlob &);
bool operator>=(const StrBlob &,const StrBlob &);
bool operator>(const StrBlob &,const StrBlob &);
bool operator<=(const StrBlob &,const StrBlob &);
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 &);
public:StrBlobPtr():curr(0){}StrBlobPtr(StrBlob &a,std::size_t sz=0):wptr(a.data),curr(sz){}StrBlobPtr(const StrBlob &a,std::size_t sz=0):wptr(a.data),curr(sz){}std::string & operator[](std::size_t i) {auto p=check(i,"index is out of range");return p->at(i);}const std::string & operator[](std::size_t i) const {auto p=check(i,"index is out of range");return p->at(i);}StrBlobPtr & operator++();StrBlobPtr operator++(int);StrBlobPtr & operator--();StrBlobPtr operator--(int);StrBlobPtr operator+(std::size_t) const;StrBlobPtr operator-(std::size_t) const;StrBlobPtr & operator+=(std::size_t);StrBlobPtr & operator-=(std::size_t);std::string & operator*() const;std::string * operator->() const;std::string &deref() const;
private:std::shared_ptr<std::vector<std::string>> check(std::size_t,const std::string &) const;std::weak_ptr<std::vector<std::string>> wptr;std::size_t curr=0;
};
bool operator==(const StrBlobPtr &,const StrBlobPtr &);
bool operator!=(const StrBlobPtr &,const StrBlobPtr &);
bool operator<(const StrBlobPtr &,const StrBlobPtr &);
bool operator>=(const StrBlobPtr &,const StrBlobPtr &);
bool operator>(const StrBlobPtr &,const StrBlobPtr &);
bool operator<=(const StrBlobPtr &,const StrBlobPtr &);
#endif

StrBlob.cpp

#include "StrBlob.h"
using namespace std;
StrBlobPtr StrBlob::begin()
{return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::begin() const
{return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{return StrBlobPtr(*this,data->size());
}
StrBlobPtr StrBlob::end() const
{return StrBlobPtr(*this,data->size());
}StrBlob::StrBlob():data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string> il):data(make_shared<vector<string>>(il)){}
StrBlob::StrBlob(const StrBlob &org):data(make_shared<std::vector<std::string>>(*org.data)) {}
StrBlob & StrBlob::operator=(const StrBlob &rhs)
{data=make_shared<std::vector<std::string>>(*rhs.data);return *this;
}
inline void StrBlob::check(size_type i,const string &msg) const
{if(i>=data->size())throw out_of_range(msg);
}
string &StrBlob::front()
{check(0,"front on empty StrBlob");return data->front();
}
string &StrBlob::back()
{check(0,"back on empty StrBlob");return data->back();
}
const std::string &StrBlob::front() const
{check(0,"front on empty StrBlob");return data->front();
}
const std::string &StrBlob::back() const
{check(0,"back on empty StrBlob");return data->back();
}
void StrBlob::pop_back()
{check(0,"pop_back on empty StrBlob");data->pop_back();
}
bool operator==(const StrBlob &lhs,const StrBlob &rhs)
{return lhs.data==rhs.data;
}
bool operator!=(const StrBlob &lhs,const StrBlob &rhs)
{return !(lhs==rhs);
}
bool operator<(const StrBlob &lhs,const StrBlob &rhs)
{return *lhs.data<*rhs.data;
}
bool operator>=(const StrBlob &lhs,const StrBlob &rhs)
{return !(lhs<rhs);
}
bool operator>(const StrBlob &lhs,const StrBlob &rhs)
{return rhs<lhs;
}
bool operator<=(const StrBlob &lhs,const StrBlob &rhs)
{return !(rhs<lhs);
}std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i,const std::string &msg) const
{auto ret=wptr.lock();if(!ret)throw std::runtime_error("unbound StrBlobPtr");if(i>=ret->size())throw std::out_of_range(msg);return ret;
}
std::string & StrBlobPtr::deref() const
{auto p=check(curr,"dereference past end");return (*p)[curr];
}
StrBlobPtr & StrBlobPtr::operator++()
{check(curr,"increment past end of StrBlobPtr");++curr;return *this;
}
StrBlobPtr StrBlobPtr::operator++(int)
{StrBlobPtr ret=*this;++*this;return ret;
}
StrBlobPtr & StrBlobPtr::operator--()
{--curr;check(curr,"decrement past the begin of StrBlobPtr");return *this;
}
StrBlobPtr StrBlobPtr::operator--(int)
{StrBlobPtr ret=*this;--*this;return ret;
}
StrBlobPtr StrBlobPtr::operator+(std::size_t i) const
{StrBlobPtr ret(*this);ret+=i;return ret;
}
StrBlobPtr StrBlobPtr::operator-(std::size_t i) const
{StrBlobPtr ret(*this);ret-=i;return ret;
}
StrBlobPtr & StrBlobPtr::operator+=(std::size_t i)
{while(i--)++*this;return *this;
}
StrBlobPtr & StrBlobPtr::operator-=(std::size_t i)
{check(curr-i,"decrement past begin of range");curr-=i;return *this;
}
std::string & StrBlobPtr::operator*() const
{auto p=check(curr,"dereference past end");return (*p)[curr];
}
std::string * StrBlobPtr::operator->() const
{return & this->operator*();
}
bool operator==(const StrBlobPtr &lhs,const StrBlobPtr &rhs)
{auto l=lhs.wptr.lock();auto r=rhs.wptr.lock();if(l==r)return (!r||lhs.curr==rhs.curr);elsereturn false;
}
bool operator!=(const StrBlobPtr &lhs,const StrBlobPtr &rhs)
{return !(lhs==rhs);
}
bool operator<(const StrBlobPtr &lhs,const StrBlobPtr &rhs)
{auto l=lhs.wptr.lock(),r=rhs.wptr.lock();if(l==r&&l)//两个指针未指向同一个vector的情况是否应该抛出异常return lhs.curr<rhs.curr;elsereturn  false;
}
bool operator>=(const StrBlobPtr &lhs,const StrBlobPtr &rhs)
{return !(lhs<rhs);
}
bool operator>(const StrBlobPtr &lhs,const StrBlobPtr &rhs)
{return rhs<lhs;
}
bool operator<=(const StrBlobPtr &lhs,const StrBlobPtr &rhs)
{return !(rhs<lhs);
}

StrVec.h

#ifndef _STRVEC_H
#define _STRVEC_H
#include <string>
#include <cstddef>
#include <utility>
#include <memory>
#include <initializer_list>
class StrVec
{friend bool operator==(const StrVec &,const StrVec &);friend bool operator!=(const StrVec &,const StrVec &);friend bool operator<(const StrVec &,const StrVec &);friend bool operator>=(const StrVec &,const StrVec &);friend bool operator>(const StrVec &,const StrVec &);friend bool operator<=(const  StrVec &,const StrVec &);public:StrVec():elements(nullptr),first_free(nullptr),cap(nullptr) {}StrVec(const StrVec &);StrVec(std::initializer_list<std::string>);StrVec & operator=(const StrVec &);StrVec & operator=(std::initializer_list<std::string>);std::string & operator[](std::size_t i) {return elements[i];}const std::string & operator[](std::size_t i) const {return elements[i];}~StrVec() {free();}void push_back(const std::string &);size_t size() const {return first_free-elements;}size_t capacity() {return cap-elements;}std::string *begin() const {return elements;}std::string *end() const {return first_free;}void resize(const size_t n,const std::string &orgv=std::string());void reserve(const size_t n);private:std::string *elements;std::string *first_free;std::string *cap;static std::allocator<std::string> alloc;void chk_n_alloc() {if(size()==capacity()) reallocate();}std::pair<std::string *,std::string *> alloc_n_copy(const std::string *,const std::string *);void free();void reallocate();
};
bool operator==(const StrVec &,const StrVec &);
bool operator!=(const StrVec &,const StrVec &);
bool operator<(const StrVec &,const StrVec &);
bool operator>=(const StrVec &,const StrVec &);
bool operator>(const StrVec &,const StrVec &);
bool operator<=(const  StrVec &,const StrVec &);
#endif

StrVec.cpp

#include <algorithm>
#include "StrVec.h"
std::allocator<std::string> StrVec::alloc;
StrVec::StrVec(const StrVec &org)
{std::pair<std::string *,std::string *> data=alloc_n_copy(org.begin(),org.end());elements=data.first;first_free=cap=data.second;
}
StrVec::StrVec(std::initializer_list<std::string> ls)
{auto data=alloc_n_copy(ls.begin(),ls.end());elements=data.first;first_free=cap=data.second;
}
StrVec & StrVec::operator=(const StrVec &rhs)
{auto data=alloc_n_copy(rhs.begin(),rhs.end());free();elements=data.first;first_free=cap=data.second;return *this;
}
StrVec & StrVec::operator=(std::initializer_list<std::string> il)
{auto data=alloc_n_copy(il.begin(),il.end());free();elements=data.first;first_free=cap=data.second;return *this;
}
void StrVec::push_back(const std::string &s)
{chk_n_alloc();alloc.construct(first_free++,s);
}
std::pair<std::string *,std::string *> StrVec::alloc_n_copy(const std::string *b,const std::string *e)
{std::string *data=alloc.allocate(e-b);return {data,uninitialized_copy(b,e,data)};
}
void StrVec::free()
{if(elements){for(auto p=first_free;p!=elements;)alloc.destroy(--p);alloc.deallocate(elements,cap-elements);}
}
void StrVec::reallocate()
{size_t newcapacity=size()?2*size():1;std::string *newdata=alloc.allocate(newcapacity);std::string *dest=newdata;std::string *src=elements;for(size_t i=0;i!=size();++i)alloc.construct(dest++,std::move(*src++));free();elements=newdata;first_free=dest;cap=elements+newcapacity;
}
void StrVec::reserve(const size_t n)
{if(n>capacity()){std::string *newdata=alloc.allocate(n);std::string *dest=newdata;std::string *src=elements;for(size_t i=0;i!=size();++i)alloc.construct(dest++,std::move(*src++));free();elements=newdata;first_free=dest;cap=elements+n;}
}
void StrVec::resize(const size_t n,const std::string &orgv)
{if(n<=size()){std::string *b=elements+n;std::string *e=first_free;while(b!=e)alloc.destroy(b++);first_free=elements+n;}else if(n<=capacity()){std::string *b=first_free;std::string *e=elements+n;while(b!=e)alloc.construct(b++,orgv);first_free=e;}else{reserve(n);std::string *b=first_free;std::string *e=elements+n;while(b!=e)alloc.construct(b++,orgv);first_free=e;}
}
bool operator==(const StrVec &lhs,const StrVec &rhs)
{return (lhs.size()==rhs.size())&&std::equal(lhs.begin(),lhs.end(),rhs.begin());
}
bool operator!=(const StrVec &lhs,const StrVec &rhs)
{return !(lhs==rhs);
}
bool operator<(const StrVec &lhs,const StrVec &rhs)
{return lexicographical_compare(lhs.begin(),lhs.end(),rhs.begin(),rhs.end());
}
bool operator>=(const StrVec &lhs,const StrVec &rhs)
{return !(lhs<rhs);
}
bool operator>(const StrVec &lhs,const StrVec &rhs)
{return rhs<lhs;
}
bool operator<=(const  StrVec &lhs,const StrVec &rhs)
{return !(rhs<lhs);
}

String.h

#ifndef _sTRING_H
#define _sTRING_H
#include <iostream>
#include <utility>
class String
{friend std::istream & operator>>(std::istream &in,String &str);friend std::ostream & operator<<(std::ostream &out,const String &str);friend bool operator==(const String &,const String &);friend bool operator!=(const String &,const String &);friend bool operator<(const String &,const String &);friend bool operator>=(const String &,const String &);friend bool operator>(const String &,const String &);friend bool operator<=(const String &,const String &);public:String():head(nullptr),tail(nullptr),cap(nullptr) {}String(const char *);String(const String &);String(String &&str) noexcept :head(str.head),tail(str.tail),cap(str.cap) {str.head=str.tail=str.cap=nullptr;std::cout<<"This is move constructor."<<std::endl;}String & operator=(const String &);String & operator=(String &&);String operator+(const String &);char & operator[](std::size_t i) {return head[i];}const char & operator[](std::size_t i) const {return head[i];}~String() {free();}size_t size() const {return tail-head;}size_t capacity() const {return cap-head;}bool empty() const {return (head==tail)?true:false;}char * begin() const {return head;}char * end() const {return tail;}private:char *head;char *tail;char *cap;static std::allocator<char> alloc;void free();std::pair<char *,char *> alloc_n_copy(const char *,const char *);void chk_n_alloc(size_t n) {if(n+size()>capacity()) reallocate(n);}void reallocate(size_t n);
};
std::istream & operator>>(std::istream &in,String &str);
std::ostream & operator<<(std::ostream &out,const String &str);
bool operator==(const String &,const String &);
bool operator!=(const String &,const String &);
bool operator<(const String &,const String &);
bool operator>=(const String &,const String &);
bool operator>(const String &,const String &);
bool operator<=(const String &,const String &);
#endif

String.cpp

#include <memory>
#include <algorithm>
#include <cstring>
#include <string>
#include "String.h"
String::String(const char *str)
{size_t n=strlen(str);std::pair<char *,char *> newdata=alloc_n_copy(str,str+n);head=newdata.first;tail=cap=newdata.second;
}
String::String(const String &s)
{std::pair<char *,char *> newdata=alloc_n_copy(s.begin(),s.end());head=newdata.first;tail=cap=newdata.second;
}
String & String::operator=(const String &rhs)
{std::pair<char *,char *> newdata=alloc_n_copy(rhs.begin(),rhs.end());free();head=newdata.first;tail=cap=newdata.second;return *this;
}
String & String::operator=(String &&rhs)
{if(this!=&rhs){free();head=rhs.head;tail=rhs.tail;cap=rhs.cap;rhs.head=rhs.tail=rhs.cap=nullptr;}return *this;
}
String String::operator+(const String &rhs)
{String tmp(*this);size_t n=rhs.size();tmp.chk_n_alloc(n);char *dest=tmp.tail;char *src=rhs.begin();for(size_t i=0;i!=6;++i)alloc.construct(dest++,*src++);tmp.tail=dest;return tmp;
}std::allocator<char> String::alloc;
void String::free()
{if(head){std::for_each(begin(),end(),[](char &c) {alloc.destroy(&c);});alloc.deallocate(head,cap-head);}
}
std::pair<char *,char *> String::alloc_n_copy(const char *b,const char *e)
{char *newdata=alloc.allocate(e-b);return {newdata,std::uninitialized_copy(b,e,newdata)};
}
void String::reallocate(size_t n)
{size_t newcap=(size()>n?size()*2:n*2);char *newdata=alloc.allocate(newcap);char *dest=newdata;char *src=head;for(size_t i=0;i!=size();++i)alloc.construct(dest++,std::move(*src++));free();head=newdata;tail=dest;cap=head+newcap;
}
std::istream & operator>>(std::istream &in,String &str)
{std::string tmp;in>>tmp;String Stmp(tmp.c_str());str=Stmp;return in;
}
std::ostream & operator<<(std::ostream &out,const String &str)
{std::for_each(str.begin(),str.end(),[&out](const char &c)->void {out<<c;});return out;
}
bool operator==(const String &lhs,const String &rhs)
{return (lhs.size()==rhs.size())&&std::equal(lhs.begin(),lhs.end(),rhs.begin());
}
bool operator!=(const String &lhs,const String &rhs)
{return !(lhs==rhs);
}
bool operator<(const String &lhs,const String &rhs)
{size_t i=0;size_t l_size=lhs.size(),r_size=rhs.size();while(i<l_size&&i<r_size){if(*(lhs.begin()+i)==*(rhs.begin()+i))++i;elsereturn *(lhs.begin()+i)<*(rhs.begin()+i);}return l_size<r_size;
}
bool operator>=(const String &lhs,const String &rhs)
{return !(lhs<rhs);
}
bool operator>(const String &lhs,const String &rhs)
{return rhs<lhs;
}
bool operator<=(const String &lhs,const String &rhs)
{return !(rhs<lhs);
}

14.17

Employee.h

#ifndef _EMPLOYEE_H
#define _EMPLOYEE_H
#include <iostream>
class Employee
{friend std::ostream & operator<<(std::ostream &,const Employee &);friend std::istream & operator>>(std::istream &,Employee &);friend bool operator==(const Employee &,const Employee &);friend bool operator!=(const Employee &,const Employee &);public:Employee()=default;Employee(std::string s):name(s){}Employee(std::string s,unsigned int i,double j,unsigned int k):name(s),Age(i),salary(j),Phone_Number(k){}Employee & operator=(const Employee &);Employee & operator=(Employee &&);Employee & operator=(const std::string &);operator bool()  const {return !(name.empty());}private:std::string name;unsigned int Age=0;double salary=0;unsigned int Phone_Number=0;
};
std::ostream & operator<<(std::ostream &,const Employee &);
std::istream & operator>>(std::istream &,Employee &);
bool operator==(const Employee &,const Employee &);
bool operator!=(const Employee &,const Employee &);
#endif

Employee.cpp

#include "Employee.h"
Employee & Employee::operator=(const Employee &rhs)
{name=rhs.name;Age=rhs.Age;salary=rhs.salary;Phone_Number=rhs.Phone_Number;return *this;
}
Employee & Employee::operator=(Employee &&rhs)
{if(this!=&rhs){name=std::move(rhs.name);Age=rhs.Age;salary=rhs.salary;Phone_Number=rhs.Phone_Number;}return *this;
}
Employee & Employee::operator=(const std::string &str)
{name=str;return *this;
}
std::ostream & operator<<(std::ostream &os,const Employee &src)
{os<<src.name<<" "<<src.Age<<" "<<src.salary<<" "<<src.Phone_Number;return os;
}
std::istream & operator>>(std::istream &is,Employee &src)
{is>>src.name>>src.Age>>src.salary>>src.Phone_Number;if(!is)src=Employee();return is;
}
bool operator==(const Employee &lhs,const Employee &rhs)
{return lhs.name==rhs.name&&lhs.Age==rhs.Age&&lhs.salary==rhs.salary&&lhs.Phone_Number==rhs.Phone_Number;
}
bool operator!=(const Employee &lhs,const Employee &rhs)
{return !(lhs==rhs);
}

14.18

见14.16

14.19

Employee类可以按雇员的名字、年龄、收入、电话号码比较,所以不存在一种逻辑可靠的<定义,所以它不应该含有关系运算符。

14.20

见14.2

14.21

 我感觉缺点不明显,性能上并没有什么损失,可读性?
Sales_data.h

#include <iostream>
#include <string>
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:std::string isbn() const {return bookNo;}Sales_data()=default;Sales_data(const std::string &s):bookNo(s) {}Sales_data(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(n*p) {}Sales_data & operator+=(const Sales_data &);private:std::string bookNo;unsigned units_sold=0;double revenue=0.0;double avg_price() const;
};
std::istream & operator>>(std::istream &,Sales_data &);
std::ostream & operator<<(std::ostream &,const Sales_data &);
Sales_data operator+(const Sales_data &,const Sales_data &);

Sales_data.cpp

#include "Sales_data.h"
inline double Sales_data::avg_price() const
{if(units_sold)return revenue/units_sold;elsereturn 0;
}
std::istream & operator>>(std::istream &is,Sales_data &src)
{double price=0.0;is>>src.bookNo>>src.units_sold>>price;if(is)src.revenue=src.units_sold*price;elsesrc=Sales_data();return is;
}
std::ostream & operator<<(std::ostream &os,const Sales_data &src)
{os<<src.isbn()<<" "<<src.units_sold<<" "<<src.revenue<<" "<<src.avg_price();return os;
}
Sales_data & Sales_data::operator+=(const Sales_data & rhs)
{*this=*(this)+rhs;return *this;
}
Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs)
{Sales_data tmp;tmp.bookNo=lhs.bookNo;tmp.units_sold=lhs.units_sold+rhs.units_sold;tmp.revenue=lhs.revenue+rhs.revenue;return tmp;
}

14.22

Sales_data.h

#include <iostream>
#include <string>
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:std::string isbn() const {return bookNo;}Sales_data()=default;Sales_data(const std::string &s):bookNo(s) {}Sales_data(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(n*p) {}Sales_data & operator+=(const Sales_data &);operator std::string() const {return bookNo;}operator double() const {return revenue;}private:std::string bookNo;unsigned units_sold=0;double revenue=0.0;double avg_price() const;
};
std::istream & operator>>(std::istream &,Sales_data &);
std::ostream & operator<<(std::ostream &,const Sales_data &);
Sales_data operator+(const Sales_data &,const Sales_data &);

Sales_data.cpp

#include "Sales_data.h"
inline double Sales_data::avg_price() const
{if(units_sold)return revenue/units_sold;elsereturn 0;
}
std::istream & operator>>(std::istream &is,Sales_data &src)
{double price=0.0;is>>src.bookNo>>src.units_sold>>price;if(is)src.revenue=src.units_sold*price;elsesrc=Sales_data();return is;
}
std::ostream & operator<<(std::ostream &os,const Sales_data &src)
{os<<src.isbn()<<" "<<src.units_sold<<" "<<src.revenue<<" "<<src.avg_price();return os;
}
Sales_data & Sales_data::operator+=(const Sales_data & rhs)
{*this=*(this)+rhs;return *this;
}
Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs)
{Sales_data tmp;tmp.bookNo=lhs.bookNo;tmp.units_sold=lhs.units_sold+rhs.units_sold;tmp.revenue=lhs.revenue+rhs.revenue;return tmp;
}

14.23

见14.16

14.24

见14.17

14.25

见14.17
 需要定义一个运算对象为string的赋值运算符,可以直接为雇员的名字赋值.

14.26

见14.16

14.27

见14.16

14.28

见14.16

14.29

 因为递增、递减运算符要改变所操作对象的状态,所以不能使用const修饰符。

14.30

见14.16

14.31

 因为StrBlobPtr的数据成员是由一个weak_ptr和一个内置类型组成,它们都能被合成的拷贝控制成员正确的处理。

14.32

PtStrBlobPtr.h

#ifndef _PTSTRBLOBPTR_H
#define _PTSTRBLOBPTR_H
#include "StrBlob.h"
class PtStrBlobPtr
{public:PtStrBlobPtr()=default;PtStrBlobPtr(StrBlobPtr *p):ptbp(p) {}StrBlobPtr & operator*() const {return *ptbp;}StrBlobPtr * operator->() const {return & this->operator*();}private:StrBlobPtr * ptbp=nullptr;
};
#endif

PtStrBlobPtr.cpp

#include "PtStrBlobPtr.h"

14.33

 因为重载的函数调用运算符可接受的参数是不一定的,所以它应该接受几个运算对象不确定。

14.34

#include <iostream>
struct func
{int operator()(int a,int b,int c) { return a>0?b:c;}
};
int main(void)
{func f;std::cout<<f(-1,2,3)<<std::endl;return 0;
}

14.35

#include <iostream>
#include <string>
struct func
{std::string operator()(){std::string tmp;getline(std::cin,tmp);return tmp;}
};
int main(void)
{func f;std::cout<<f()<<std::endl;return 0;
}

14.36

#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
struct func
{std::string operator()(){std::string tmp;getline(std::cin,tmp);return tmp;}
};
int main(void)
{vector<string> svec;func f;while(cin)svec.push_back(f());for(const auto a:svec)cout<<a<<endl;return 0;
}

14.37

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
class func
{public:func(int tg=0):targ(tg) {}bool operator()(int rec) {return rec==targ;}private:int targ=0;
};
int main(void)
{func f(1);vector<int> a{0,1,2,1,3,4,5},b;replace_copy_if(a.begin(),a.end(),back_inserter(b),f,99);for(auto r:b)cout<<r<<endl;return 0;
}

14.38

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class func
{public:func(size_t n):sz(n) {}bool operator()(const string &str) {return str.size()==sz;}private:size_t sz=0;
};
int main(int argc,char *argv[])
{string tmp;size_t wl1=0,wl2=0,wl10=0;func f1(1),f2(2),f10(10);ifstream  in(argv[1]);while(in>>tmp){if(f1(tmp))++wl1;if(f2(tmp))++wl2;if(f10(tmp))++wl10;}in.close();cout<<"长度为1的单词有"<<wl1<<" 长度为2的单词有"<<wl2<<" 长度为10的单词有"<<wl10<<endl;return 0;
}

14.39

#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class func
{public:func(size_t n):sz(n) {}bool operator()(const string &str) {return str.size()>sz;}private:size_t sz=0;
};
int main(int argc,char *argv[])
{string tmp;size_t wl1=0,wl2=0,wl10=0;func f1(0),f2(9),f10(10);ifstream  in(argv[1]);while(in>>tmp){if(f1(tmp))++wl1;if(f2(tmp))++wl2;if(f10(tmp))++wl10;}in.close();cout<<"长度为1-9的单词有"<<wl1-wl2<<" 长度大于10的单词有"<<wl10<<endl;return 0;
}

14-40

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
struct func1
{bool operator()(const string &str1,const string &str2) {return str1.size()<str2.size();}
};
class func2
{public:func2(size_t n):sz(n) {}bool operator()(const string &str) {return str.size()>=sz;}private:size_t sz;
};
struct func3
{void operator()(const string &str) {cout<<str<<" ";}
};
void elimDups(vector<string> &s)
{sort(s.begin(),s.end());auto end_unique=unique(s.begin(),s.end());s.erase(end_unique,s.end());
}
string make_plural(size_t count,const string &word,const string &end)
{return (count>1)?(word+end):word;
}
void biggies(vector<string> &words,vector<string>::size_type sz)
{elimDups(words);stable_sort(words.begin(),words.end(),func1());auto wc=find_if(words.begin(),words.end(),func2(sz));auto count=words.end()-wc;cout<<count<<" "<<make_plural(count,"word","s")<<" of length "<<sz<<" or longer "<<endl;for_each(wc,words.end(),func3());cout<<endl;
}
int main(void)
{string tmp;vector<string> svec;cout<<"Enter some strings: ";while(cin>>tmp)svec.push_back(tmp);biggies(svec,3);return 0;
}

14.41

lambda就是匿名的函数对象,当这个函数对象只在少数地方使用,并且函数体足够简单时,适合使用lambda表达式。而这个函数对象需要多次复用,并且函数体较复杂时,使用类。

14.42

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
void elimDups(vector<int> &s)
{sort(s.begin(),s.end());auto end_unique=unique(s.begin(),s.end());s.erase(end_unique,s.end());
}
string make_plural(size_t count,const string &word,const string &end)
{return (count>1)?(word+end):word;
}
void biggies(vector<int> &words,vector<int>::size_type sz)
{elimDups(words);stable_sort(words.begin(),words.end(),less<int>());auto wc=find_if(words.begin(),words.end(),bind(greater<int>(),std::placeholders::_1,sz));//在这里auto count=words.end()-wc;cout<<count<<" "<<make_plural(count,"word","s")<<" greater than "<<sz<<endl;cout<<endl;
}
int main(void)
{int tmp;vector<int> ivec;cout<<"Enter some integers: ";while(cin>>tmp)ivec.push_back(tmp);biggies(ivec,1024);return 0;
}
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
int main(void)
{string tmp;vector<string> svec;cout<<"Enter some strings: ";while(cin>>tmp)svec.push_back(tmp);auto wc=find_if(svec.begin(),svec.end(),bind(not_equal_to<string>(),std::placeholders::_1,"pooh"));//在这里if(wc==svec.end())cout<<"All are pooh."<<endl;elsecout<<"Find the string not equal to pooh."<<endl;return 0;
}
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
int main(void)
{int tmp;vector<int> ivec,ivec_backup;cout<<"Enter some integers: ";while(cin>>tmp)ivec.push_back(tmp);transform(ivec.begin(),ivec.end(),back_inserter(ivec_backup),bind(multiplies<int>(),std::placeholders::_1,2));//在这里cout<<"multiply by two:";for(auto i:ivec_backup)cout<<i<<" ";cout<<endl;return 0;
}

14.43

#include <iostream>
#include <vector>
#include <functional>
using namespace std;
int main(void)
{bool flag=true;int targ,tmp;vector<int> ivec;cout<<"输入要判断的那个int值:";cin>>targ;cout<<"输入一系列int值创建一个int容器:";while(cin>>tmp)ivec.push_back(tmp);for(const int &i:ivec){if(modulus<int>()(targ,i)!=0){flag=false;break;}}if(flag)cout<<"可以被整除"<<endl;elsecout<<"不能被整除"<<endl;return 0;
}

14.44

#include <iostream>
#include <map>
#include <functional>
#include <string>
using namespace std;
int add(int i,int j) {return i+j;}
int main(void)
{struct divide{int operator()(int denominator,int divisor) {return denominator/divisor;}};auto mod=[](int x,int y)->int {return x%y;};map<string,function<int(int,int)>> binops={{"+",add},{"-",minus<int>()},{"*",[](int x,int y) {return x*y;}},{"/",divide()},{"%",mod}};int a,b;string op;cout<<"输入 数字 算术符号 数字:";cin>>a>>op>>b;cout<<"结果是"<<binops[op](a,b)<<endl;return 0;
}

14.45

见14.22
 转换为string时应该返回bookNo。转换为double时到底应该返回revenue还是返回avg_price不确定,它们之间不存在明确的一对一对应关系。

14.46

 可以为Sales_data定义string类型转换运算符,但建议声明成explicit,可以防止在某些情况下被默认转换成string,导致意料之外的运算结果。不建议定义double类型转换运算符,因为它不存在明确的一对一对应关系。

14.47

  • 转换为const int
  • 转换为int,此const表示const函数,即不会修改待转换对象内容。

14.48

 它应该含有向bool的类型转换运算符,并且应该是explicit的,可以避免被默认转换成bool,导致意料之外的运算结果。此类型转换可以用在条件判断处,而explicit的类型转换运算符用在条件判断时可以被隐式的执行。

14.49

见14.17

14.50

  • 因为没有直接转换为int型的用户定义的类型转换,所以得先转换为算术类型,再执行算术类型转换。而第一步中两个用户定义的类型转换一样好,所以产生二义性。
  • 直接调用operator float()类型转换。

14.51

会直接调用void calc(int),因为标准类型转换优先于用户定义的类型转换。

14.52

  • 二义性调用
  • 1,2都可以,1成员函数是精确匹配,2中si需要先利用用户定义的类型转换,转换为int,再进行标准类型转换,转换为double。所以调用1.

14.53

 不合法,会产生二义性。SmallInt可以转换为int调用内置类型的+号,3.14可以转换为SmallInt而调用其重载的+号。可以这样该double d=s1+SmallInt(3.14)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/732330.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实现QT中qDebug()的日志重定向

背景&#xff1a; 在项目开发过程中&#xff0c;为了方便分析和排查问题&#xff0c;我们需要将原本输出到控制台的调试信息写入日志文件&#xff0c;进行持久化存储&#xff0c;还可以实现日志分级等。 日志输出格式&#xff1a; 我们需要的格式包括以下内容&#xff1a; 1.…

MySQL死锁详细介绍

首先死锁产生的原因&#xff1a;两个及以上事务争夺资源导致互相等待造成的 比如事务A先修改id为1的数据再去修改id为2的数据&#xff0c;事务B先修改id为2的数据再去修改id为1的数据&#xff0c;因为事务A先拿到id1的锁再去拿id2的锁&#xff0c;而事务B先拿到id2的锁又去拿id…

“成像光谱遥感技术中的AI革命:ChatGPT应用指

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用&#xff0c;人工智能…

【Algorithms 4】算法(第4版)学习笔记 16 - 4.2 有向图

文章目录 前言参考目录学习笔记1&#xff1a;介绍1.1&#xff1a;有向图简介1.2&#xff1a;应用举例1.3&#xff1a;相关问题2&#xff1a;有向图 API2.1&#xff1a;有向图表示2.1.1&#xff1a;邻接表数组 Adjacency-list2.1.2&#xff1a;Java 实现&#xff1a;邻接表数组2…

2. gin中间件注意事项、路由拆分与注册技巧

文章目录 一、中间件二、Gin路由简介1、普通路由2、路由组 三、路由拆分与注册1、基本的路由注册2、路由拆分成单独文件或包3、路由拆分成多个文件4、路由拆分到不同的APP 一、中间件 在日常工作中&#xff0c;经常会有一些计算接口耗时和限流的操作&#xff0c;如果每写一个接…

Sftp服务器搭建(linux)

Sftp服务器搭建&#xff08;linux&#xff09; 一、基本工作原理 FTP的基本工作原理如下&#xff1a; 1&#xff09;建立连接&#xff1a;客户端与服务器之间通过TCP/IP建立连接。默认情况下&#xff0c;FTP使用端口号21作为控制连接的端口。​​​​​​​ 2&#xff09;身…

基于AI软件平台 HEGERLS智能托盘四向车机器人物流仓储解决方案持续升级

随着各大中小型企业对仓储需求的日趋复杂&#xff0c;柔性、离散的物流子系统也不断涌现&#xff0c;各种多类型的智能移动机器人、自动化仓储装备大量陆续的应用于物流行业中&#xff0c;但仅仅依靠传统的物流技术和单点的智能化设备&#xff0c;已经无法更有效的应对这些挑战…

Office 2007软件安装教程(附软件下载地址)

软件简介&#xff1a; 软件【下载地址】获取方式见文末。注&#xff1a;推荐使用&#xff0c;更贴合此安装方法&#xff01; 微软Office 2007是一款具有重大创新与革命性的办公软件套件。它引入了全新设计的用户界面&#xff0c;提供稳定安全的文件格式&#xff0c;并实现了无…

数据结构 - 堆(优先队列)+ 堆的应用 + 堆练习

文章目录 前言堆一、什么是堆二、堆又分为大根堆和小根堆三、由于堆的逻辑结构被看成完全二叉树&#xff0c;那么我们先来了解一下完全二叉树。四、堆使用数组还是链表储存数据呢&#xff1f;五、数组构建二叉树和父子节点之间的定位六、堆进行的操作七、实现小根堆1、堆的初始…

算法(数据结构)面试问题准备 二分法/DFS/BFS/快排

一、算法概念题 1. 二分法 总结链接几种查找情况的模板另一个好记的总结总结&#xff1a;搜索元素两端闭&#xff0c;while带等&#xff0c;mid1&#xff0c;结束返-1 搜索边界常常左闭右开&#xff0c;while小于&#xff0c;mid看边界开闭&#xff0c;闭开&#xff0c;结束i…

vue2【详解】生命周期(含父子组件的生命周期顺序)

1——beforeCreate&#xff1a;在内存中创建出vue实例&#xff0c;数据观测 (data observer) 和 event/watcher 事件配置还没调用&#xff08;data 和 methods 属性还没初始化&#xff09; 【执行数据观测 (data observer) 和 event/watcher 事件配置】 2——created&#xf…

指纹加密U盘/指纹KEY方案——采用金融级安全芯片 ACH512

方案概述 指纹加密U盘解决方案可实现指纹算法处理、数据安全加密、数据高速存取&#xff08;EMMC/TF卡/NandFlash&#xff09;&#xff0c;可有效保护用户数据安全。 方案特点 • 采用金融级安全芯片 ACH512 • 存储介质&#xff1a;EMMC、TF卡、NandFlash • 支持全系列国密…

解决白屏问题:让你的网站重焕生机

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

[Flutter]使用Provider进行状态管理

一、使用Provider进行状态管理的基本用法 Provider是Flutter中一个非常流行的状态管理工具&#xff0c;它可以帮助开发者更有效地管理Widget树中的数据。Provider的核心思想是将数据模型放置在Widget树中可以被多个子Widget访问的地方&#xff0c;而不必通过构造函数手动传递。…

软件测试 —— 如何测试图片上传功能?

作为一名专业的软件测试人员&#xff0c;测试图片上传功能是一个重要的任务&#xff0c;以下是一些测试该功能的常用方法&#xff1a; 1. 上传功能测试&#xff1a;确保图片上传功能正常工作&#xff0c;包括选择图片文件、点击上传按钮、上传进度显示、上传成功/失败的提示等。…

JavaWeb03-HTTP协议,Tomcat,Servlet

目录 一、HTTP协议 1.概述 2.特点 3.请求数据格式 &#xff08;1&#xff09;请求行 &#xff08;2&#xff09;请求头 &#xff08;3&#xff09;请求体 &#xff08;4&#xff09;常见请求头 &#xff08;5&#xff09;GET和POST请求区别 4.响应数据格式 &#xf…

gRPC-第二代rpc服务

在如今云原生技术的大环境下&#xff0c;rpc服务作为最重要的互联网技术&#xff0c;蓬勃发展&#xff0c;诞生了许多知名基于rpc协议的框架&#xff0c;其中就有本文的主角gRPC技术。 一款高性能、开源的通用rpc框架 作者作为一名在JD实习的Cpper&#xff0c;经过一段时间的学…

Flask python开发篇: 写一个简单的接口

第一步&#xff1a;新建flask项目 参考使用pycharm新建一个项目 打开pycharm&#xff0c;根据下面图中箭头顺序&#xff0c;新建一个flask的项目&#xff1b; 第二步&#xff1a;运行项目&#xff0c; 安装成功以后&#xff0c;会有个app.py文件&#xff0c;打开以后&#…

qt一个项目有且只有有一个maindow,其他小窗口用QWidget,QDialog是带有yes和no的QWidget

QMaindow QWidget QDialog区别很大 我想要在生成一个小窗口&#xff0c;结果选择基类为maindow&#xff0c;应该是QWidget 然后就出现奇奇怪怪的问题 QMaindow和QWidget不能乱选择&#xff0c;而且各自QPaintEvent也有很多区别 以下就是错误&#xff1a; 我继承maindow的基类…

【物联网设备端开发】物联网设备上云提供开箱即用接入SDK

&#x1f308; 个人主页&#xff1a;帐篷Li &#x1f525; 系列专栏&#xff1a;物联网设备端开发 &#x1f4aa;&#x1f3fb; 物联网设备上云提供开箱即用接入SDK 目录 一、项目介绍 二、项目目录 三、集成方式 四、设备功能开发 4.1 连接与消息 4.2 业务功能 4.3 运维…