友元函数及运算符

友元函数

  • friend关键字
  • 类中的private关键字修饰的成员都不能在类之中进行访问。
  • 作用: 在类之外达到可以访问私有成员的目的。

形式:

1、普通函数
2、成员函数
3、友元类
//普通函数写法
#include<bits/stdc++.h>
using namespace std;

class Point {
	public:
	Point(int ix=0,int iy=0)
	:_ix(ix)
	,_iy(iy)
	{
	}
	void print() const{
		cout<<"("<<_ix
		<<","<<_iy<<")"<<endl;
	}
	//友元之普通函数
	friend double getDistance(const Point &lhs,const Point &rhs);
	private:
	int _ix;
	int _iy;
};
double getDistance(const Point &lhs,const Point &rhs){
	return sqrt((lhs._ix-rhs._ix)*(lhs._ix-rhs._ix)+
				(lhs._ix-rhs._ix)*(lhs._ix-rhs._ix));
}
void test0(){
	Point pt1(1,2),pt2(3,4);
	cout<<"pt1:";
	pt1.print();
	cout<<"pt2:";
	pt2.print();

	cout<<"the distance:"<<getDistance(pt1,pt2)<<endl;
}
int main(){
	test0();
	return 0;
}
//成员函数
#include <bits/stdc++.h>
using namespace std;
class Point;//类的前向声明
class Line
{
public:
	//在函数声明中,是不需要知道Point的具体内容
	//此时可以给出该类的前向声明形式
	double getDistance(const Point &lhs, const Point &rhs);
};
class Point
{
public:
	Point(int ix = 0, int iy = 0)
		: _ix(ix), _iy(iy)
	{
	}
	void print() const
	{
		cout << "(" << _ix
			 << "," << _iy << ")" << endl;
	}
	//2、友元之成员函数
	friend double Line::getDistance(const Point &lhs, const Point &rhs);

private:
	int _ix;
	int _iy;
};
double Line::getDistance(const Point &lhs, const Point &rhs)
	{
		return sqrt((lhs._ix - rhs._ix) * (lhs._ix - rhs._ix) +
					(lhs._ix - rhs._ix) * (lhs._ix - rhs._ix));
	}
void test0()
{
	Point pt1(1, 2), pt2(3, 4);
	cout << "pt1:";
	pt1.print();
	cout << "pt2:";
	pt2.print();
	Line line;
	cout << "the distance:" << line.getDistance(pt1, pt2) << endl;
}
int main()
{
	test0();
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
class Point;//类的前向声明
class Line
{
public:
	//在函数声明中,是不需要知道Point的具体内容
	//此时可以给出该类的前向声明形式
	double getDistance(const Point &lhs, const Point &rhs);
	
	void setPoint(Point &pt,int x,int y);
};
class Point
{
public:
	//友元之友元类
	friend class Line;
	Point(int ix = 0, int iy = 0)
		: _ix(ix), _iy(iy)
	{
	}
	void print() const
	{
		cout << "(" << _ix
			 << "," << _iy << ")" << endl;
	}
private:
	int _ix;
	int _iy;
};
double Line::getDistance(const Point &lhs, const Point &rhs)
	{
		return sqrt((lhs._ix - rhs._ix) * (lhs._ix - rhs._ix) +
					(lhs._ix - rhs._ix) * (lhs._ix - rhs._ix));
	}
void Line::setPoint(Point &pt,int x,int y){
	pt._ix=x;
	pt._iy=y;
}
void test0()
{
	Point pt1(1, 2), pt2(3, 4);
	cout << "pt1:";
	pt1.print();
	cout << "pt2:";
	pt2.print();
	Line line;
	line.setPoint(pt2,5,6);
	cout << "the distance:" << line.getDistance(pt1, pt2) << endl;
}
int main()
{
	test0();
	return 0;
}

友元是否破坏了类的封装性

  • 确实破坏了

  • 友元做了一些限制:

    1、友元不能被继承

    2、友元是单向的,不具备传递性

    3、友元不具备传递性

比如Line是Point的友元,但是Point并未为line单独声明,因此无法访问Line中的

运算符重载

希望自定义类型在使用时与内置类型的数据操作在形式上保持一致

规则:

1、运算符重载的参数类型只能是自定义类类型和枚举类型。

//内置类型的运算符无法重载
int operator+(int x,int y){
	return x-y;
}

2、重载之后,运算符的优先级和结合性还是固定的

3、&& | | 重载之后,就不再具备短路求值特性。

也就是左边的表达式为假,右边的就不需要进行运算了

4、有几个运算符不能重载的:

sizeof //在编译期就已经得到值了,比较早
.  //无法重载
?: 
.* //成员指针访问运算符
::  

5、不能臆造一个并不存在的运算符

形式:

  • 普通函数
//参数形式都为const,因为执行之后参数是不修改的,保持不变的
Complex operator +(const Complex &lhs,const Complex &rhs){
	return Complex(lhs.getReal()+rhs.getReal(),lhs.getImage()+rhs.getImage());
}
//同时,普通函数不使用友元的话,需要拿get函数支撑
  • 成员函数
  • 友元函数

特殊运算符重载

复合赋值运算符

  • 建议使用成员函数的形式进行重载
	Complex &operator+=(const Complex &rhs){
		this->_dreal+= this->_dreal;
		this->_dimage+=rhs._dimage;
		return *this;
	}//记得上面的引用,不然就会调用拷贝构造函数

自增自减运算符

  • 前置形式与后置形式是有差异;后置形式的参数列表会多一个int,与前置形式进行区分,不需要传参,同时

前置形式的效率更高

下标访问运算符

  • vector、map内部也重载了下标访问运算符
#include<bits/stdc++.h>
using namespace std;
class CharArray
{
public:
	CharArray(const char *pdata)
	:_capacity(strlen(pdata)+1)
	,_pdata(new char [_capacity]())
	{
		strcpy(_pdata,pdata);
	}
	int size() const{return _capacity-1;}

	char &operator[](int idx){
		cout<<"char &operator[]"<<endl;
		if(idx>=0&&idx<=size()){
		return _pdata[idx];
		}
		else {
			static char nullchar='\0';
			return nullchar;
		}
	}//如果返回char,会自动进行复制
	~CharArray(){
		if(_pdata){
			delete[]_pdata;
		}
	}
private:
	size_t _capacity;
	char *_pdata;
};
void test0(){
	CharArray ca("hellowuhan");
	for(int idx=0;idx<ca.size();idx++){
		cout<<ca[idx]<<endl;
	}
	cout<<endl;
}
int main(){
	test0();
	return 0;
}

成员访问运算符

实现String类的其它运算符的重载

class String 
{
public:
	String();
	String(const char *);
	String(const String &);
	~String();
	String &operator=(const String &);
	String &operator=(const char *);

	String &operator+=(const String &);
	String &operator+=(const char *);
	
	char &operator[](std::size_t index);
	const char &operator[](std::size_t index) const;
	
	std::size_t size() const;
	const char* c_str() const;
	
	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 &);
	
	friend std::ostream &operator<<(std::ostream &os, const String &s);
	friend std::istream &operator>>(std::istream &is, String &s);

private:
	char * _pstr;
};

String operator+(const String &, const String &);
String operator+(const String &, const char *);
String operator+(const char *, const String &);

提示:将上面自定义String的所有函数重新实现一下,注意有些函数是可以相互调用的,这个代码不难,但是相对来说比较繁琐,可以写一个测试一个,降低错误率。

#include<bits/stdc++.h>
using namespace std;
class String
{
	private:
	char *_pstr;
	public:
	String()
	:_pstr(new char[1]())//初始化
	{
		cout<<"String()"<<endl;
	}
	String(const char *pstr)
	:_pstr(new char[strlen(pstr)+1]()){//重载
		cout<<"String(const char *)"<<endl;
		strcpy(_pstr,pstr);
	}
	String(const String &rhs)
	:_pstr(new char[strlen(rhs._pstr)+1]()){
		cout<<"String(const String &)"<<endl;
		strcpy(_pstr,rhs._pstr);
	}
	~String()//析构
	{
		cout<<"~String()"<<endl;
		if(_pstr){
			delete[]_pstr;
			_pstr=nullptr;
		}
	}
	String &operator=(const String &rhs)
	{
		cout << "String &operator=(const String &)" << endl;
		if (this != &rhs)
		{
			delete[] _pstr;
			_pstr = nullptr;
			_pstr = new char[strlen(rhs._pstr) + 1]();
			strcpy(_pstr, rhs._pstr);
		}
		return *this;
	}
	String &operator=(const String *pstr){
		cout<<"String &operator=(const char*)"<<endl;
		String tmp(*pstr);
		*this = tmp;
		return *this;
	}
	String &operator+=(const String &rhs){
		cout<<"String &operator+=(const String &rhs)"<<endl;
		String tmp;
		tmp._pstr=new char[strlen(_pstr)+1]();
		strcpy(tmp._pstr,_pstr);
		delete []_pstr;
		_pstr=nullptr;
		_pstr=new char[strlen(rhs._pstr)+strlen(tmp._pstr)+1]();
		strcpy(_pstr,tmp._pstr);
		strcat(_pstr,rhs._pstr);
		return *this;
	}
	String &operator+=(const char *pstr){
		cout<<"String &operator+=(const char *pstr)"<<endl;
		String tmp(pstr);
		*this+=tmp;
		return *this;
	}
	char &operator[](std::size_t index){
		if(index<size()){
			return _pstr[index];
		}else{
			static char nullchar='\0';//必须加static
			return nullchar;
		}
	}
	const char&operator[](std::size_t index)const{
		if(index<size()){
			return _pstr[index];
		}else{
			static char nullchar='\0';//必须加static
			return nullchar;
		}
	}
	std::size_t size() const
	{
		return strlen(_pstr);
	}

	const char *c_str() const
	{
		return _pstr;
	}
	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 &);

	friend std::ostream &operator<<(std::ostream &os, const String &rhs);
	friend std::istream &operator>>(std::istream &is, String &rhs);
};
bool operator==(const String &lhs, const String &rhs)
{
    return !strcmp(lhs._pstr, rhs._pstr);
}

bool operator!=(const String &lhs, const String &rhs)
{
    return strcmp(lhs._pstr, rhs._pstr);
}

bool operator<(const String &lhs, const String &rhs)
{
    return strcmp(lhs._pstr, rhs._pstr) < 0;
}

bool operator>(const String &lhs, const String &rhs)
{
    return strcmp(lhs._pstr, rhs._pstr) > 0;
}
bool operator<=(const String &lhs, const String &rhs)
{
    return strcmp(lhs._pstr, rhs._pstr) <= 0;
}
bool operator>=(const String &lhs, const String &rhs)
{
    return strcmp(lhs._pstr, rhs._pstr) >= 0;
}
std::ostream &operator<<(std::ostream &os, const String &rhs){
	if(rhs._pstr){
		os<<rhs._pstr;
	}
	return os;
}
std::istream &operator>>(std::istream &is, String &rhs){
	if(rhs._pstr){
		delete []rhs._pstr;
		rhs._pstr=nullptr;
	}
	vector<char>buff;
	char ch;
	while((ch=is.get())!='\n'){
		buff.push_back(ch);//输出不为回车时一直输入
	}
	rhs._pstr=new char[buff.size()+1]();
	strncpy(rhs._pstr,&buff[0],buff.size());
	return is;
}
String operator+(const String &lhs, const String &rhs)
{
    cout << "String operator+(const String &, const String &)" << endl;

    String tmp(lhs);
    tmp += rhs;

    return tmp;
}
String operator+(const String &lhs, const char *pstr)
{
    cout << "String operator+(const String &, const char *)"<< endl;
    String tmp(lhs);
    tmp += pstr;

    return tmp;

}
String operator+(const char *pstr, const String &rhs)
{
    cout << "String operator+(const char*, const String &)" << endl;
    String tmp(pstr);
    tmp += rhs;

    return tmp;

}
void test0(){
    String s1;
    cin >> s1;
    cout << "s1 = " << s1 << endl;

    cout << endl << endl;
    String s2 = "hello";
    cout << "s2 = " << s2 << endl;

    cout << endl << "nihao" <<  endl;
    s2 = "wangdao"; //error
    cout << "s2 = " << s2 << endl;

    cout << endl << endl;
    s2 = s2;
    cout << "s2 = " << s2 << endl;

    cout << endl << endl;
    String s3 = "C++";
    s3 += " haonan";
    cout << "s3 = " << s3 << endl;
}
int main(){
	test0();
	return 0;
}
//输出
jing@jing:~/code/2022-4-5$ ./2
String()
nohello
s1 = nohello


String(const char *)
s2 = hello

nihao
String(const char *)
String &operator=(const String &)
~String()
s2 = wangdao


String &operator=(const String &)
s2 = wangdao


String(const char *)
String &operator+=(const char *pstr)
String(const char *)
String &operator+=(const String &rhs)
String()
~String()
~String()
s3 = C++ haonan
~String()
~String()
~String()
posted @   Fancele  阅读(237)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示