C++primer-学习心得-14-重载运算与类型转换

31 篇文章 3 订阅

C++primer-学习心得-14-重载运算与类型转换

14.1 基本概念

可以被重载的运算符有:

+-*/%^
&|~!`=
<><=>=++
<<>>==!=&&||
+=-=/=%=^=&=
|=*=<<=>>=[]()
->->*newnew[]deletedelete[]

不能被重载的运算符:

:: .* . ?:

有两种调用运算符的函数:

data1+data2;
operator+(data1,data2);

这两种调用是等价的。

我们像调用其他成员函数一样显示地调用成员函数运算符函数。

data1+=data2;
data1.operator+=(data2);

有一个必须注意的问题是双目运算符是在类的外部定义,这本来是很合理的,双目运算符其实不能看作类的成员函数,而应是类的友元函数。具体需要注意的一些细节自己实际操作的时候就会注意到了。

练习14.2,14.6,14.9,14.20,14.21,14.22

这个类包含了输入、输出、加法、复合运算(+=),正好是这几个题要求的

#include<string>
#include<iostream>

using namespace std;
class sales_data {
	friend istream& operator>>(istream&, sales_data&);
	friend ostream& operator<<(ostream&, const sales_data&);
	friend sales_data& operator+(sales_data&, sales_data&);
public:
	sales_data(string s,unsigned u, double d) :bookid(s), sold(u), avenue(d) {}//构造函数
	sales_data():sales_data("", 0, 0.0) {}
	string getbookid() { return bookid; }
	sales_data(const sales_data& s) :bookid(s.bookid), sold(s.sold),avenue(s.avenue){}//拷贝构造函数
	sales_data& operator=(const sales_data& s){  //拷贝赋值运算符
		bookid = s.bookid;
		sold = s.sold;
		avenue =s.avenue;
		return *this;
	}
	sales_data& operator=(const string& str) {
		bookid = str;
		return *this;
	}
	~sales_data() = default;//析构函数
	//不需要移动操作
	sales_data& operator+=( sales_data&);

private:
	string bookid;
	unsigned sold;
	double avenue;
};
istream& operator>>(istream& is, sales_data& s) {
	is >> s.bookid >> s.sold >> s.avenue;
	return is;
}
ostream& operator<<(ostream& o,const sales_data& s) {
	o << s.bookid << "--" << s.sold << "---" << s.avenue;
	return o;
}
sales_data& operator+(sales_data& l, sales_data& r) {
	if (l.bookid == r.bookid) {
		l.sold += r.sold;
		l.avenue += r.avenue;
		return l;
	}
	else {
		cout << "无效的加法" << endl;
		return l;
	}
}
sales_data& sales_data::operator+=(sales_data&r) {
	return (*this) + r;
}

int main() {
	sales_data s1("aaa", 10, 100), s2("aaa", 20, 200), s3;
	cin >> s3;
	cout << s1 << endl;
	cout << s2;
	cout << s3;
	cout << s1 + s2 << endl;
	s2 += s1;
	cout << s2 << endl;
	s3 = s1 + s2;
	s3 = "test";
	cout << s3 << endl;
}

14.2 输入和输出运算符

输入运算符必须要处理输入可能失败的情况,而输出运算符不需要。

执行输入运算符时可能发生以下错误:

  • 当流含有错误类型的数据时读取操作可能失败。(如需要读入一个int类型结果输入的是string,读取操作及后续的操作也会失败。
  • 读取操作到达文件的末尾或者遇到输入流的其他错误时也会失败。

14.3 算术和关系运算符

需要注意的主要是区分双目运算符和单目运算符。

对于关系运算符,如果要用到顺序容器,那么定义operator<会很有必要。

14.4 赋值运算符

14.5下标运算符

下标运算符必须是成员函数。

14.6 递增和递减运算符

这两个运算符都有前置版本和后置版本。

区别为

\\前置
strblobptr& operator++();
strblobptr& operator--();
\\后置
strblobptr& operator++(int);
strblobptr& operator--(int);

为了区分前置和后置,我们为后置提供一个额外的int类型形参,这个形参不会参与运算。

14.7成员访问运算符

这些知识都不难,用起来也非常便利,如下是一个例子

#include<iostream>
#include<memory>
using namespace std;

struct pointer {
	int i;
	shared_ptr<pointer>p;
	~pointer() { p.reset(); }
};
class ptr;
class iters {
	friend ptr;
	friend bool operator==(iters& l, iters& r);
	friend bool operator!=(iters& l, iters& r);
public:
	iters() = default;
	iters(int i, shared_ptr<pointer>p) :it(&i), pt(p) {}
	~iters() { pt.reset(); }
	iters& operator++() {
		pt = pt->p;
		it = &(pt->i);
		//cout << "++" << endl;
		return *this;
	}
	iters& operator++(int){
		pt = pt->p;
		it = &(pt->i);
		//cout << "++" << endl;
		return *this;
	}
	int operator*()const {
		//cout << "*" << endl;
		return *it;
	}
private:
	int* it;
	shared_ptr<pointer>pt;
};
bool operator==(iters& l, iters& r) {
	if (l.it == r.it)
		return true;
	else
		return false;
}
bool operator!=(iters& l, iters& r) {
	if (l.it == r.it)
		return false;
	else
		return true;
}

class ptr {
public:
	ptr() :beg(new pointer) { beg->p = nullptr; }
	~ptr() { beg.reset(); }//beg是唯一指向该对象的指针,析构函数会释放对象,释放对象时对象的成员p又会被销毁然后释放对象,
	//最终把所有的内存释放了,理论上会这样,但实际上会不会这么做并不清楚。也只有智能指针可以这么做
	void insert(int start, int data) {
		if (size() == 0 ) {
			shared_ptr<pointer>pa(new pointer);
			beg->i = data;
			beg->p = pa;
			pa->p = nullptr;
		}
		else if (start <= size()) {
			shared_ptr<pointer>pp(beg),pa(new pointer);
			if (start == 0) {
				pa->p = beg->p;
				beg -> p = pa;
				pa->i = beg->i;
				beg->i = data;
			}else{
				for (int i = 0; i < start-1; i++)
					pp = pp->p;
				pa->p = pp->p;
				pp->p = pa;
				pa->i = data;
			}
		}
	}
	int at(int order) {
		if (order < size()) {
			shared_ptr<pointer>pa(beg);
			for (int i = 0; i < order; i++)
				pa = pa->p;
			return pa->i;
		}
	}
	int operator[](int order) { return at(order); }
	void push_back(int data) {
		insert(size(), data);
	}
	void push_front(int data) {
		insert(0, data);
	}
	int size() {
		int i = 0;
		shared_ptr<pointer>pp(beg);
		while (pp->p != nullptr) {
			i++;
			pp = pp->p;
		}
		return i;
	}
	void del(int order) {
		if (order < size()) {
			if (order == 0) {
				beg->i = beg->p->i;
				beg->p = beg->p->p;//.resize()更好点,似乎
			}
			else {
				shared_ptr<pointer>pa(beg);
				for (int i = 0; i < order-1; i++)
					pa = pa->p;
				pa->p = pa->p->p;
			}
		}
	}
	void pop_back() {
		del(size() - 1);
	}
	void pop_front() {
		del(0);
	}
	
	iters& begin();
	iters& end();
private:
	shared_ptr<pointer> beg;
	iters itt;
};

iters& ptr::begin() {
	itt.it=&(beg->i);
	itt.pt = beg;
	return itt;
}
iters& ptr::end() {
	shared_ptr<pointer>pa(beg);
	for (int i = 0; i < size(); i++)
		pa = pa->p;
	itt.it = &(pa->i);
	itt.pt = pa;
	return itt;
}
int main() {
	ptr test;
	test.push_back(0);
	test.push_back(1);
	test.push_back(2);
	test.push_front(4);
	test.del(1);
	test.pop_back();
	for (int i = 0; i < test.size(); i++) {
		cout << test[i] << endl;
	}
	test.push_back(111);
	cout << *(test.begin()) << endl;
	for (auto it = test.begin(); it != test.end(); ++it)
		cout << *it << endl;
}

这个程序花费了我很多时间,将我之前的单向链表的包括插入、删除的各种操作包装到一个类。甚至提供了类似迭代器的遍历容器的方式。还是挺有意思的。完全要靠自己去考虑怎么实现这个想法。

14.8 函数调用运算符

一个简单的例子如:

struct absInt{
    int operator()(int val)const{
return val<0?-val:val;}
}
int i=-42;
absInt absobj;
int ui=absobj(i);

如果类定了调用运算符,则该类的对象称为函数对象

练习14.34
#include<iostream>
#include<string>
using namespace std;
struct ite {
	int operator()(bool a1, int a2, int a3) {
		return a1 ? a2 : a3;
	}
};

int main() {
	ite test;
	int aa = test(true, 3, 5);
	cout << aa << endl;
}
练习14.35
#include<iostream>
#include<string>
using namespace std;
class prints {
public:
	prints(istream& iss = cin) :is(iss) {}
	string operator()() {
		string s;
		if (getline(is, s))
			return s;
		else
			return " ";
	}
private:
	istream& is;
};
int main() {
	prints test;
	string testt = test();
	cout << testt << endl;
}
练习14.36
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class prints {
public:
	prints(istream& iss = cin) :is(iss) {}
	string operator()() {
		string s;
		if (getline(is, s)) {
			strvec.push_back(s);
			return s;
		}	
		else
			return " ";
	}
private:
	istream& is;
	vector<string>strvec;
};
int main() {
	prints test;
	string testt = tesdt();
	cout << testt << endl;
}

1.lambda是函数对象

stable_sort(words.begin(),words.end(),[](const string&a,const string &b){
return a.size()<b.size();
});
//类似的
class Shorterstring{
    public bool operator()(const string &a,const string &b){
        return a.size()<b.size();
    }
};

有捕获行为的类

auto wc=find_if(words.begin(),words.end(),[sz](const string&a){return a.size()>=sz;});
//类似
class sizecomp{
    public:
    sizecomp(size_t n):sz(n){}
    bool operator()(const string &s)const{
        return s.size()>=sz;
        private:
        size_t sz;
    }
}
auto wc=find_if(words.begin(),words.end(),sizecomp(sz));

2.标准库定义的函数对象

标准库定义了一组表示算术运算符、关系运算符和逻辑运算符的类,每个类分别定义了一个执行命名操作的调用运算符。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值