记录C++的学习2

记录c++的学习2

(仅供参考,欢迎大家交流学习)
2021.1.10

4、友元:

4.1全局函数做友元:

1、友元的目的就是让一个函数或者类访问另一个类中私有成员
2、友元的关键字为friend
3、友元的三种实现
(1)全局函数做友元
(2)类做友元
(3)成员函数做友元
4、友元是C++提供的一种破坏数据封装和数据隐藏的机制。
5、若一个类为另一个类的友元,则此类的所有成员函数都能访问对方类的私有成员。
6、单向性:如果声明B类是A类的友元, B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。不可传递性,不可继承性:。

下面展示一些 代码

#include <iostream>
#include <string>
using namespace std;
class Person
{
    
    
	//友元函数声明:
	friend void test01(Person *p);
public:
	Person()
	{
    
    
		home="我家";
		phone="我手机";
	}
	string home;
private:
	string phone;
};
//全局函数:
void test01(Person *p)//用指针或者是用引用都可以
{
    
    //不过用指针就必须是p->home,引用是p.home
	cout<<"好朋友来"<<p->home<<endl;
	cout<<"好朋友可以看"<<p->phone<<endl;
}
void test02()
{
    
    
	Person p;
	test01(&p);//传入指针,所以用&p
	
}
int main()
{
    
    
	test02();
	system("pause");
	return 0;
}

在这里插入图片描述

4.2 类做友元:

下面展示一些 代码

#include <iostream>
#include <string>
using namespace std;
//类做友元:
//若一个类为另一个类的友元,则此类的所有成员函数都能访问对方类的私有成员。
class A
{
    
    
	friend class B;//赋予B类友元的权限
public:
	void Display()//设置一个函数输出x的值
	{
    
    
		cout<<x<<endl;
	}
private:
	int x;
};
class B
{
    
    
public:
	void Set(int i)
{
    
    
	a.x=i;
	/*因为A类赋予了B类友元关系,故在B类中可以直接访问
	A类对象a的私有数据成员*/

}
	void Display()
{
    
    
	a.Display();
}
private:
	A a;

};
void test01()
{
    
    
	B a;
	a.Set(3);
	a.Display();
}
int main()
{
    
    
test01();
system("pause");
return 0;
}

在这里插入图片描述

4.3 成员函数做友元:

5、运算符重载:

5.1 加号运算符重载:

1、不能利用成员函数重载<<运算符,因为无法实现cout在左侧,只能利用全局函数重载左移运算符。
2、进行重载,就是在operator函数里面完成我们想要的操作。然后用这个运算符的时候,就把它当一个普通符号,可以完成我们想要的操作符号。即,我们用这个运算符的目的是什么, 搞清楚目的后,我们就根据目的写操作。

#include <iostream>
using namespace std;
//加号运算符重载
//1、成员函数重载+号
class Person
{
    
    
public:
	/*Person operator+(Person &p)
	{
		Person temp;
		temp.a=this->a+p.a;//this->a是指自身当前对象a的属性加上传进来的a的属性。
		temp.b=this->b+p.b;
		return temp;
	}*/
int a;
int b;
};
//void test01()
//{
    
    
//	Person p1;
//	p1.a=10;
//	p1.b=10;
//	Person p2;
//	p2.a=10;
//	p2.b=10;
//	Person p3;
//	p3=p1+p2;
//	cout<<"P3.a="<<p3.a<<endl;
//	cout<<"P3.b="<<p3.b<<endl;
//}
//2、全局函数重载+号
Person operator+(Person &p3,Person &p4)
{
    
    
	Person temp1;
	temp1.a=p3.a+p4.a;
	temp1.b=p3.b+p4.b;
	return temp1;
}
Person operator+(Person &p3,int num)
{
    
    
	Person temp1;
	temp1.a=p3.a+num;
	temp1.b=p3.b+num;
	return temp1;
}
//Person P3=p1.operator+(p2)简化为Person p3=p1+p2;
void test02()
{
    
    
	Person p3;
	p3.a=15;
	p3.b=15;
	Person p4;
	p4.a=15;
	p4.b=15;
	Person p5;
	p5=p3+p4;
	cout<<"P5.a="<<p5.a<<endl;
	cout<<"P5.b="<<p5.b<<endl;
    Person  p6;
	p6=p3+100;
	cout<<"P6.a="<<p6.a<<endl;
	cout<<"P6.b="<<p6.b<<endl;
}
//成员函数重载本质调用:
//Person p3=p1.operator+(p2);

//全局函数重载本质调用
//Person p3=operator+(p1,p2);

//运算符重载,也可以发生函数重载

int main()
{
    
    
	
	test02();
	system("pause");
	return 0;
}

在这里插入图片描述

5.2 左移运算符重载:

#include <iostream>
using namespace std;
class Person
{
    
    
	friend ostream & operator<<(ostream &cout,Person &p);//运用友元函数访问private
public:
	Person (int a,int b)
	{
    
    
		this->a=a;
		this->b=b;
	}
private:
	int a;
	int b;

};
/*利用成员函数重载 左移运算符 p.operator<<(cout) 简化为p<<cout。
不能利用成员函数重载<<运算符,因为无法实现cout在左侧*/
//只能利用全局函数重载左移运算符:
ostream & operator<<(ostream &cout,Person &p)//本质 operator<<(cout,p),简化为cout<<p
//输出流对象,全局只能有一个,用引用的方式传递。
{
    
    
	cout <<"a="<<p.a<<endl;
	cout <<"b="<<p.b<<endl;
	return cout;
}
void test01()
{
    
    
	Person p(1024,1024);
	cout<<p;
}
int main()
{
    
    
	test01();
	system("pause");
	return 0;
}

在这里插入图片描述

5.3 递增运算符重载:

#include <iostream>
using namespace std;
//重载递增运算符

//自定义整型
class MyInteger
{
    
    
	friend ostream & operator<<(ostream& cout,MyInteger &myint);
public:
	MyInteger()
	{
    
    
		num=0;
		  
	}
	//重载前置++运算符
	MyInteger& operator++()
	//必须用引用&,目的是一直对一个数据进行操作
	{
    
    
	//先进行++运算
	num++;
	//再将自身做一个返回
	return *this;//*this,将自身作为返回
	}
	//重载后置++运算符
	//int代表占位参数,可以用于区分前置和后置递增
	MyInteger operator++(int)//后置返回值,前置返回引用
	{
    
    
	//先记录当时结果
	MyInteger temp=*this;
	//后递增
	num++;
	//最后将记录结果做一个返回操作
	return temp;
	}
private:
	int num;

};
void test01()
{
    
    
	MyInteger myint;
	cout<<++myint<<endl;
	cout<<myint<<endl;
}
void test02()
{
    
    
	MyInteger myint;
	cout<<myint++<<endl;
	cout<<myint<<endl;
}
ostream & operator<<(ostream& cout,MyInteger &myint)
{
    
    
	cout<<myint.num;
	return cout;
}
int main()
{
    
    
	cout<<"前置++运算符:"<<endl;
	test01();
	cout<<"后置++运算符:"<<endl;
	test02();
	system("pause");
	return 0;
}

在这里插入图片描述

5.4 赋值运算符重载:

1、赋值运算符operator=,对属性进行拷贝,如果有属性指向堆区,做赋值操作时,也会出现深浅拷贝的问题。

#include <iostream>
using namespace std;
//赋值运算符重载
class Person
{
    
    
public:
	Person(int age1)
	{
    
    
	age=new int(age1);
	}
	~Person()
	{
    
    
		//堆区内存重复释放,会导致程序崩溃。
		if(age!=NULL)
		{
    
    
			delete age;
			age=NULL;
		}
	}
	//重载 赋值运算符
	Person& operator=(Person &p)
	{
    
    
		//编译器提供浅拷贝age=p.age;

		//应该先判断是否有属性在堆区,如果有,先释放干净,然后再深拷贝。
		if(age!=NULL)
		{
    
    
			delete age;
			age=NULL;
		}
		age=new int (*p.age);//深拷贝
		//返回对象本身
		return *this;
	}
  int *age;
};
void test01()
{
    
    
	Person p1(18);
	Person p2(20);
	Person p3(25);
	p3=p2=p1;
	p2=p1;//赋值操作
	cout<<"p1的年龄为:"<<*p1.age<<endl;
	cout<<"p2的年龄为:"<<*p2.age<<endl;
	cout<<"p3的年龄为:"<<*p3.age<<endl;
}
int main()
{
    
    
	test01();
	system("pause");
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45960449/article/details/112424324
今日推荐