记录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;
}