//注意这是 非成员 运算符函数的等价调用
data1 + data2;
operator+(data1, data2);
//注意这是对成员运算符函数的等价调用
data1 += data2;
data1.operator+=(data2);
//如果运算符定义成成员函数,左侧运算对象必须是运算符所属类的一个对象
string s = "world";
string t = s + "!"; //正确
string u = "hi" + s; //这里如果string将+定义成成员函数,将发生错误
//如果string将+定义为成员运算符函数
//则"hi" + s等价为"hi".operator+(s);
//但是"hi"是内置类型const char*,根本没有什么operator+成员函数
//但是string将+定义为普通的非成员函数
//所以这里实际是operator+("hi", s);
ostream &operator<<(std::ostream &os, const Sales_data &item)
{os << item.isbn() << " " << item.units_sold << " "<< venue << " " << item.avg_price();return os;
}
istream &operator>>(std::istream &is, Sales_data &item)
{double price;is >> item.bookNo >> item.units_sold >> price;if (is) //检查输入是否成功venue = price * item.units_sold;elseitem.Sales_data(); //输入失败就赋予默认状态return is;
}
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{Sales_data sum = lhs;sum += rhs;return sum;
}
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{return lhs.isbn() == rhs.isbn() &&lhs.units_sold == rhs.units_sold &&venue == venue;
}
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{return !(lhs == rhs);
}
vector<string> v;
v = {"a", "ab", "abc"};
StrVec &StrVec::operator=(initializer_list<string> il)
{auto data = alloc_n_copy(il.begin(), il.end());//下面内容和拷贝赋值运算符一致free();elements = data.first;first_free = cap = data.second;return *this;
}
//因为initializer_list<string>确保il和this指的不是同一个对象
//所以不用考虑自赋值
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{units_sold += rhs.units_sold;revenue += venue;return *this;
}
class StrVec
{
public:string& operator[](size_t n) { return elements[n]; }const string& operator[](size_t n) const { return elements[n]; }
//...
private:string *elements;
};
//...
StrVec svec;
const StrVec cvec = svec;
if (svec.size() && svec[0].empty()) //如果svec有元素且第一个元素为空
{svec[0] = "zero"; //正确,下标运算符返回string的引用//相当于svec.operator[](0) = "zero",返回引用的函数得到左值,所以能在运算符左侧cvec[0] = "Zip"; //错误!对cvec取下标返回的是常量引用//相当于cvec.operator[](0) = "Zip",因为返回值是常量引用,所以不能修改对象的值
}
class StrBlobPtr
{
public:StrBlobPtr operator++();StrBlobPtr operator--();
};
//原来的incr函数,现在改写成自增
StrBlobPtr& StrBlobPtr::opeartor++()
{check(curr, "increment past end of StrBlobPtr");++curr;return *this;
}
StrBlobPtr& StrBlobPtr::opeartor--()
{//这里避免出现curr本身是0的情况,如果本身是0则递减会产生一个无效下标--curr;check(curr, "decrement past begin of StrBlobPtr");return *this;
}
class StrBlobPtr
{
public:StrBlobPtr operator++(int); //后置版本StrBlobPtr operator--(int);
};
//注意现在返回的都不是引用了
//并且都不用检查有效性,只有前置才检查
StrBlobPtr StrBlobPtr::opeartor++(int)
{StrBlobPtr ret = *this; //记录当前值++*this; //向前移动一个元素,然后因为前置++,所以会检查有效性return ret;
}
StrBlobPtr StrBlobPtr::opeartor--(int)
{StrBlobPtr ret = *this;--*this;return ret;
}
//可以看得出,后置版本都是调用前置版本来完成实际工作的
StrBlobPtr p(a1);
p.operator++(0); //调用后置版本
p.operator++(); //调用前置版本
//要想调用后置版本,传入的值必不可少
class StrBlobPtr
{
public:string& operator*() const{auto p = check(curr, "dereference past end");//检查p是否在正确范围内,是则返回curr所指元素的引用return (*p)[curr];//(*p)是对象所指的vector}string* operator->() const{//将工作委托给解引用运算符return &this->operator*();//调用解引用运算符,并返回解引用结果元素的地址}
};
StrBlob a1 = {"hi", "bye", "now"};
StrBlobPtr p(a1); //p指向a1中的vector
*p = "okay"; //给a1首元素赋值
cout << p->size() << endl; //输出4,即okay的长度
cout << (*p).size() << endl;
point->mem;
//如果point是指针,我们会用内置的箭头运算符,表达式会等价于(*point).mem//如果point是定义了operator->的类的对象
//则使用point.operator()的结果获取mem
struct absInt
{int operator()(int val) const{ return val < 0 ? -val : val; }
};
int i = -42;
absInt absObj;
int ui = absObj(i);
//看起来就像调用函数一样,但要记得absObj是对象
class PrintString
{
public:PrintString(ostream &o = cout, char c = ' ') : os(o), sep(c) {}void operator()(const string &s) const { os << s << sep; }
private:ostream &os;char sep;//os和sep用来协助调用运算符打印string
};
class SmallInt
{
public:SmallInt(int i = 0) : val(i){if (i < 0 || i > 255)throw out_of_range("Bad Smallint value");}operator int() const { return val; }
private:size_t val;
};
//这里int能转换成SmallInt,也能从SmallInt转换成int
SmallInt si;
si = 4; //4隐式转换成SmallInt,然后使用拷贝赋值运算符
si + 3; //si隐式转换成int,然后相加
si = 3.14; //内置先将double转换成int,然后同上
si + 3.14; //同上
class SmallInt
{
public://加上了explicexplicit operator int() const { return val; }
};
SmallInt si = 3; //正确,构造函数不是显式的
si + 3; //现在就错误了,因为explic不允许隐式转换
static_cast<int>(si) + 3; //正确,显式转换
struct B;
struct A
{A() = default;A(const B&);
};
struct B
{operator A() const;
};
A f(const A&);
B b;
A a = f(b); //发生二义性错误!
//这里究竟是f(B::operator A())
//还是f(A::A(const B&))?
//只能显式调用来执行正确的操作
A a1 = f(b.operator A());
A a2 = f(A(b));
struct A
{A(int = 0); //最好不要创建两个转换源都是算术类型的类型转换A(double);operator int() const; //最好不要创建两个转换对象都是算术类型的类型转换operator double() const;//其他
};
void f2(long double);
A a;
f2(a); //使用的是f(A::operator int())//还是f(A::operator double())呢long lg;
A a2(lg); //使用的是A::A(int)还是A::A(double)呢
//这里会产生二义性是因为标准类型转换级别一致
//long向double转还是向int都差不多
//下面就不会发生二义性问题
short s = 42;
A a3(s);
//因为short提升为int优于转换为double
struct C
{C(int);
};
struct D
{D(int);
};
void manip(const C&);
void manip(const D&);
manip(10); //产生二义性
//可以显式地构造正确地类型manip(C(10))消除二义性
struct E
{E(double);
};
void manip2(const C&);
void manip2(const E&); //还是二义性错误
//调用重载函数时,如果多个用户定义的类型转换都提供了可行匹配
//则我们认为这些类型一样好。并且不会考虑任何可能出现的标准类型转换的级别
class SmallInt
{friend SmallInt operator+(const SmallInt&, const Small&);
public:SmallInt(int = 0);operator int() const { return val; }
private:size_t val;
};
SmallInt s1, s2;
SmallInt s3 = s1 + s2; //使用重载的+
int i = s3 + 0; //二义性错误
//为什么会发生二义性错误呢?
//因为这句既可以理解成把s3转换成int,然后使用内置加法
//也可以理解成将0转换成SmallInt,使用重载的加法
本文发布于:2024-02-01 22:27:09,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170679762639837.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |