文章目录
一、友元
友元的目的就是让一个函数或者类 访问另一个类中私有成员
友元的关键字:friend
友元的三种实现
- 全局函数做友元
- 类做友元
- 成员函数做友元
1.全局函数做友元
friend 全局函数
代码如下(示例):
class build
{
//告诉编译器 goodgay是全局函数 是 build类的好朋友,可以访问类中的私有内容
friend void goodgay(build* building);
public:
build() //初始化
{
this->m_redroom = "卧室";
this->m_sittingroom = "客厅";
}
public:
string m_sittingroom; //客厅
private:
string m_redroom; //卧室
};
void goodgay(build* building)
{
cout << "好基友正在访问:" << building->m_sittingroom << endl;
cout << "好基友正在访问:" << building->m_redroom << endl;
}
void test01()
{
build b;
goodgay(&b);
}
2. 类做友元
friend 类
代码如下(示例):
#include<iostream>
using namespace std;
class build;
class goodgay
{
public:
goodgay(); //构造函数
void visit();
private:
build* building; //创建指针
};
class build
{
//告诉编译器 goodgay 是 build类的好朋友,可以访问类中的私有内容
friend class goodgay;
public:
build(); //可以在类内声明,在类外定义函数
public:
string m_sittingroom; //客厅
private:
string m_redroom; //卧室
};
build::build()
{
this->m_redroom = "卧室";
this->m_sittingroom = "客厅";
}
goodgay::goodgay()
{
building = new build; //在堆区创建一个类,并用指针指向它
}
void goodgay::visit() //用goodgay类中的指针访问build类中的私有成员
{
cout << "好基友正在访问:" << building->m_sittingroom << endl;
cout << "好基友正在访问:" << building->m_redroom << endl;
}
void test01()
{
goodgay b;
b.visit();
}
int main()
{
test01();
return 0;
}
3. 成员函数做友元
friend void goodgay::visit();
代码如下(示例):
#include<iostream>
using namespace std;
class build;
class goodgay
{
public:
goodgay();
void visit(); //让visit函数可以访问build中私有成员
void visit2(); //让visit2函数不可以访问build中私有成员
build* building; //创建指向build类的指针
};
class build
{
//告诉编译器 goodgay类下的visit函数作为本类的好朋友,可以访问私有成员
friend void goodgay::visit();
public:
build(); //可以在类内声明,在类外定义函数
public:
string m_sittingroom; //客厅
private:
string m_redroom; //卧室
};
//类外实现成员函数
build::build()
{
this->m_redroom = "卧室";
this->m_sittingroom = "客厅";
}
goodgay::goodgay()
{
building = new build;
}
void goodgay::visit()
{
cout << "visit函数正在访问:" << building->m_sittingroom << endl;
cout << "visit函数正在访问:" << building->m_redroom << endl;
}
void goodgay::visit2()
{
cout << "visit2函数正在访问:" << building->m_sittingroom << endl;
//cout << "visit函数正在访问:" << building->m_redroom << endl;这个会报错,因为不是build类的好朋友
}
void test01()
{
goodgay gg;
gg.visit();
}
int main()
{
test01();
return 0;
}
二、C++运算符重载
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
1. 加号运算符重载
作用:实现两个自定义数据类型相加的运算
- 成员函数重载+号
person operator+ (形参)
- 全局函数重载+号
person operator+(形参1, 形参2);
代码如下(示例):
#include<iostream>
using namespace std;
class person
{
public:
//1.成员函数重载+号
/*person operator+ (person& p)
{
person temp;
temp.m_a = this->m_a + p.m_a;
temp.m_b = this->m_b + p.m_b;
return temp;
}*/
int m_a;
int m_b;
};
//2.全局函数重载+号
person operator+ (person& p1, person& p2)
{
person temp;
temp.m_a = p1.m_a + p2.m_a;
temp.m_b = p1.m_b + p2.m_b;
return temp;
}
//函数重载的版本
person operator+ (person& p1, int num)
{
person temp;
temp.m_a = p1.m_a + num;
temp.m_b = p1.m_b + num;
return temp;
}
void test01()
{
person p1;
p1.m_a = 10;
p1.m_b = 10;
person p2;
p2.m_a = 10;
p2.m_b = 10;
//1.成员函数重载本质调用
//person p3 = p1.operator+(p2);
//2.全局函数重载本质调用
//person p3 = operator(p1,p2);
person p3 = p1 + p2;
cout << p3.m_a << endl;
cout << p3.m_b << endl;
//运算符重载 也可以发生函数重载
person p4 = p1 + 100; // person + int
cout << p4.m_a << endl;
cout << p4.m_b << endl;
}
int main()
{
test01();
return 0;
}
总结1:对于内置的数据类型的表达式的运算符是不可能改变的
总结2:不要滥用运算符重载
2.左移运算符重载
作用:可以输出自定义数据类型
全局函数 ostream& operator<<(ostream& out, person& p)
cout<<p1;
我们可以定义输出
代码如下(示例):
#include<iostream>
using namespace std;
class person
{
friend ostream& operator<<(ostream& out, person& p);
public:
person(int a, int b)
{
this->m_a = a;
this->m_b = b;
}
//成员函数 实现不了 p<<cout 不是我们想要的效果
//void operator<<(person &p){}
private:
int m_a;
int m_b;
};
//全局函数实现左移重载
//ostream对象只能有一个
ostream& operator<<(ostream& out, person& p) //out是别名 ostream:输出流,是一个类型
{
out << "a:" << p.m_a << "b:" << p.m_b;
return out;
}
void test()
{
person p1(10, 20);
cout << p1 << "hello world" << endl; //链式编程
}
int main()
{
test();
return 0;
}
3. 递增运算符重载
作用:通过重载递增运算符,实现自己的整型数据
代码如下(示例):
#include<iostream>
using namespace std;
class myinteger {
friend ostream& operator<<(ostream& out, myinteger myint);
public:
myinteger()
{
m_num = 0;
}
//前置++
myinteger& operator++()
{
//先++
m_num++;
//再返回
return *this;
}
//后置++
myinteger operator++ (int) //占位函数
{
//先返回
myinteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++
m_num++;
return temp;
}
private:
int m_num;
};
//前置++ 先++,后返回
void test01()
{
myinteger myint;
cout << ++myint << endl;
cout << myint << endl;
}
//后置++ 先返回 再++
void test02()
{
myinteger myint;
cout << myint++ << endl;
cout << myint << endl;
}
ostream& operator<<(ostream& out, myinteger myint)
{
out << myint.m_num;
return out;
}
int main()
{
test01();
//test02();
system("pause");
return 0;
}
4. 赋值运算符重载
C++编译器至少给一个类添加4个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
- 赋值运算符 operator= , 对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
代码如下(示例):
#include<iostream>
using namespace std;
class person
{
public:
person(int age)
{
//将年龄数据开辟到堆区
m_age = new int(age);
}
//重载赋值运算符
person& operator=(person& p)
{
//判断对象属性是否为空
if (m_age != NULL)
{
delete m_age;
m_age = NULL;
}
//编译器提供的代码是浅拷贝
//m_age = p.m_age
//提供深拷贝,解决浅拷贝的问题
m_age = new int(*p.m_age);
//返回自身
return *this;
}
~person()
{
if (m_age != NULL)
{
delete m_age;
m_age = NULL;
}
}
int* m_age;
};
void test01()
{
person p1(18);
person p2(20);
person p3(30);
p3 = p2 = p1; //赋值操作
cout << *p2.m_age << endl;
cout << *p3.m_age << endl;
}
//浅拷贝会报错,因为重复释放同一块内存
int main()
{
test01();
//test02();
system("pause");
return 0;
}
总结:要将对象1的值赋值给对象2,若对象1中的值创建在堆区,需要进行赋值运算符重载,
先判断对象2的属性是否为空,清理后,再深拷贝
5.关系运算符重载
作用:重载关系运算符,可以让两个自定义类型对象进行对比操作
bool operator==(引用形参)
bool operator!=(引用形参)
代码如下(示例):
#include<iostream>
using namespace std;
class person
{
public:
person(string name, int age)
{
this->m_age = age;
this->m_name = name;
};
bool operator==(person& p)
{
if (this->m_age == p.m_age && this->m_name == p.m_name)
{
return true;
}
else {
return false;
}
}
bool operator !=(person& p)
{
if (this->m_age == p.m_age && this->m_name == p.m_name)
{
return false;
}
else {
return true;
}
}
string m_name;
int m_age;
};
void test01()
{
//int a = 0;
//int b = 0;
person a("哈哈", 18);
person b("呵呵", 18);
if (a == b)
{
cout << "a和b相等" << endl;
}
else {
cout << "a和b不相等" << endl;
}
if (a != b)
{
cout << "a和b不相等" << endl;
}
else {
cout << "a和b相等" << endl;
}
}
int main()
{
test01();
//test02();
system("pause");
return 0;
}
6.函数调用运算符重载
- 函数调用运算符()也可以重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定写法,非常灵活
void operator()(形参)
代码如下(示例):
#include<iostream>
using namespace std;
#include<string>
class myprint
{
public:
void operator()(string text)
{
cout << text << endl;
}
};
void test01()
{
//重载的()操作符 也称为仿函数
myprint myfunc;
myfunc("hello world");
}
class myadd
{
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
void test02()
{
myadd add;
int ret = add(10, 10);
cout << "ret = " << ret << endl;
//匿名对象调用
cout << "myadd()(100,100) = " << myadd()(100, 100) << endl; //使用完后就释放了
}
int main()
{
test01();
test02();
system("pause");
return 0;
}