作者也是新手,笔记中或许有不足,如果有疑问可以在评论区指出更正,希望谅解。
1.1成员函数做友元
一个类的成员函数访问另一个类的属性。当需要访问私有属性时,需要在另一个类中进行说明,访问其他属性时可以不声明。
class Friend
{
public:
void visit(){}
}
class Buliding
{
friend void visit();//声明Friend的成员函数visit是这个类的友元函数,可以访问私有属性
private:
string m_Bedroom="卧室";
}
1.2重载运算符:有的类的属性可能是通过几个类的属性运算获得,但是编译器并不知道该如何运算,因此使用运算符重载告知编译器如何运算得到结果。
1.2.1加号重载
(1)成员函数重载
class Person
{
public:
//Person p3=p1.operator+(p2);
Person operator+(Person& p)//成员函数重载+号
{
Person temp;
temp.A = this->A + p.A;
temp.B = this->B + p.B;
return temp;
}
int A;
int B;
}
void test1()
{
Person p1;
p1.A = 10;
p1.B = 10;
Person p2;
p2.A = 10;
p2.B = 10;
Person p3=p1+p2; //Person p3=p1.operator+(p2);
cout << "p3.A=" << p3.A << endl;
cout << "p3.B=" << p3.B << endl;
}
int main()
{
test1();
return 0;
}
(2)全局函数重载
class Person
{
public:
int A;
int B;
}
//Person p3=operator+(p1,p2);
Person operator+(Person& p1, Person& p2)//全局函数重载+号
{
Person temp;
temp.A = p1.A + p2.A;
temp.B = p1.B + p2.B;
return temp;
}
void test1()
{
Person p1;
p1.A = 10;
p1.B = 10;
Person p2;
p2.A = 10;
p2.B = 10;
Person p3=p1+p2;//Person p3=operator+(p1,p2);
cout << "p3.A=" << p3.A << endl;
cout << "p3.B=" << p3.B << endl;
}
int main()
{
test1();
return 0;
}
1.2.2左移号重载
只能用全局函数,因为成员函数重载p.operator<<(cout)简化版本为p<<cout,而我们要的是cout<<p。
class Person
{
public:
int m_A;
int m_B;
}
ostream &operator(ostream &cout,Person &p)//全局函数,本质:cout<<p,ostream是输出流类型
{
cout<<p.m_A<<endl<<p.m_B;//这个函数的类型是输出流,相比于void,它可以做输出链
}
1.2.3递增号重载
//重载前置++运算符(++i)
MyInteger &operator++()
{
++m_Num;
return *this; //将类本身做返回
}
//重载后置++运算符(i++)
MyInteger operator++(int) //int 代表占位参数,用于区分前置和后置递增
{
MyInteger temp = *this;
m_Num++;
return temp; //将类本身做返回,局部变量temp会被释放,因此返回值而不是引用&
}
(1).重载前置运算符不需要传入参数,而重载后置运算符需要传入一个占位参数int;
(2).重载前置运算符返回的是引用,后续可以对该值继续链式调用; 重载后置运算符直接返回局部变量的值,因为局部变量在函数调用完后就被释放,所以如果引用一个局部变量地址就会报错。
1.2.4赋值符号重载
编译器默认的赋值运算符为浅拷贝(拷贝对象和原对象指向同一片存储空间,可能引发释放问题),因此在拷贝类的属性时需要将赋值运算符重载,进行深拷贝(拷贝对象和原对象指向不同存储空间),以解决堆区重复释放问题。
Person &operator=(Person& p)
{
//先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
if (m_Age)
{
delete m_Age;//释放堆区
m_Age = NULL;
}
//深拷贝
m_Age = new int(* p.m_Age);//设置新堆区
return *this;//返回本身
}
1.2.5关系运算符重载
编译器并不知道如何比较自定义数据类型的关系,因此需要重载关系运算符告知编译器如何比较
关系运算符一共有6种:==、!=、<、>、<=、>=
这里主要就 == 和 != 进行讲解,其他类似
值得注意的是,关系运算符要成对重载,比如== 和 != 都要重载
class Person
{
public:
Person(string name,int age)
{
m_Name=name;
m_Age=age;
}
string m_Name;
int m_Age;
bool operator==(Person &p)//判断是否要使用布尔类型
{
if(this->m_Name==p.m_Name && his->m_Age==p.m_Age)
return true;
else
return false;//布尔类型返回是和否
}
bool operator!=(Person &p)//重载了==就要重载!=,成对重载
{
if(this->m_Name==p.m_Name && his->m_Age==p.m_Age)
return false;//因为!=是不相等的意思,所以如果属性相等,那么应该判断否
else
return true;//不等则判断是
}
}
1.2.6函数调用运算符重载
函数调用运算符是()
class Add
{
public:
int operator()(int p1,int p2)//两个整型相加结果还是整型
{
return p1+p2;
}
}
void test1
{
Add add;
cout<<add(10,10)<<endl;
cout<<Add()(10,10)<<endl;//Add()是匿名对象,起到跟add一样的作用
}
因为函数调用运算符重载很像函数,所以也被叫做仿函数,仿函数的作用十分灵活。
还在学习中.......