c++(八)
//运算符重载
//对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
//编译器简化了一个通用名称,当你重载的函数名称为operator+时,Person p1=p1.operator+(p2) 就简化为Person p3=p1+p2;
class Person
{
//成员函数重载运算符+
//public:
/*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;
}*/
public:
int m_A;
int m_B;
};
//也可以进行函数重载
Person operator+(Person &p1,int num)
{
Person temp;
temp.m_A = p1.m_A +num;
temp.m_B = p1.m_B + num;
return temp;
}
//全局运算符重载+
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;
}
void test01()
{
Person p1;
p1.m_A = 10;
p1.m_B = 10;
Person p2;
p2.m_A = 10;
p2.m_B = 10;
Person p3 = p1 + p2;
//成员函数重载的本质调用 Person p3=p1.operator+(p2);
//全局函数重载的本质调用 Person p3=operator+(p1.p2);
cout << "p3.m_A=" << p3.m_A << endl;
cout << "p3.m_B=" << p3.m_B << endl;
Person p4=p1+100;//使用函数重载
cout << "p4.m_A=" << p4.m_A << endl;
cout << "p4.m_B=" << p4.m_B << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
//但是要注意对于内置的数据类型的表达式的运算符是不可能改变的
左移运算符
//左移运算符重载
class Person
{
public:
//利用成员函数来重载左移运算符
//void operator<<(Person &p){}当不知道返回什么的时候可以先写void,当你的参数传入的是Person
//时表示p.operator<<(p1),需要两个对象这样是不对的,因为我们想要的是
//当你cout<<p;是表示输出p中的m_A和m_B
//void operator<<(cout){}当这样写的时候,你简化之后会是p<<cout 和我们想要的是一个完全相反的情况
//所以我们通常不会使用成员函数重载左移运算符
int m_A;
int m_B;
};
//只能运用全局运算符去重载左移运算符
void operator<<(ostream &cout,Person &p)//本质是operator<<(cout,p)简化形式cout<<p cout的数据类型是输出流对象
{
cout << "m_A=" << p.m_A << endl;
cout << "m_B=" << p.m_B << endl;
//void在这里可以改为ostream & 然后加一个return cout;这样就可以进行链式编程了
}
void test01()
{
Person p1;
p1.m_A = 10;
p1.m_B = 10;
//cout << "p1.m_A=" << p1.m_A << endl;
//cout << "p1.m_B=" << p1.m_B << endl;
cout << p1;
}
int main()
{
test01();
system("pause");
return 0;
}
如果只做到这里的话,你需要再加一个换行<endl;这时系统就会崩溃的
因为cout<<p1<<endl;相当于是链式编程,返回值不能是void,因为链式编程的时候第一个参数是cout
所以如果想要继续编程的话,需要返回ostream的cout
递增运算符重载
实现自己的整型数据
引用语法:Type& name = var;
规则:1、普通引用在声明时必须用其它的变量进行初始化
2、引用作为函数参数声明时不进行初始化
匿名对象可以理解为是一个临时对象,一般系统自动生成的,如你的函数返回一个对象,这个对象在返回时会生成一个临时对象。
1.产生匿名对象的三种情况:
1)以值的方式给函数传参;
Cat(); —> 生成了一个匿名对象,执行完Cat( )代码后,此匿名对象就此消失。这就是匿名对象的生命周期。
Cat cc = Cat(); —>首先生成了一个匿名对象,然后将此匿名对象变为了cc对象,其生命周期就变成了cc对象的生命周期。
2)类型转换;
3)函数需要返回一个对象时;return temp;
//重载递增运算符
//自定义整型
class MyInteger
{
friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
MyInteger()
{
m_Num = 0;
}
//重载前置++运算符
MyInteger& operator++()
{
//先进行++运算
m_Num++;
//再将自身做一个返回,返回的是引用,是因为要返回原来的数,对一个数据进行操作,不是返回新对象
return *this;
}
//重载后置++运算符,返回值不可以作为重载的条件,加了int之后编译器就会认为是后置++,int是指占位参数区分前置和后置递增
//返回值不是返回引用是因为,这里的temp是局部对象,局部函数结束之后,局部对象就被释放,
//不满足链式编程,因为temp已经被释放
MyInteger operator++(int)
{
//先记录当时结果
MyInteger temp = *this;
//后递增
m_Num++;
//最后将纪录结果做返回
return temp;
}
private:
int m_Num;
};
//因为cout<<m<<endl;时不知道<<输出整型 MyInteger中的哪一个数据,要进行运算符重载,这里的myint不是使用的引用是因为
//后置++运行的局部变量,不结束就释放掉了,用&就指向空内存了
//<<接的后++返回值是MyInteger型,所以<<传入参数用MyInteger才不会出错,cout<<myint++,这里myint++返回的是一个局部变量的值,不加引用。匿名对象无法初始化引用
ostream& operator<<(ostream& cout, MyInteger myint)
{
cout << "m_Num=" << myint.m_Num ;
return cout;
}
void test01()
{
MyInteger m;
cout<<++(++m)<<endl;
cout << m << endl;
}
void test02()
{
MyInteger m;
cout << m++ << endl;
cout << m << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
c++编译器至少给一个类添加5个函数
1.默认构造函数(无参)
2.默认析构函数(无参)
3.默认拷贝函数,对属性进行值拷贝
4.赋值运算符operator=,对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
//赋值运算符重载
class person
{
public:
person(int age)
{
m_age=new int(age);//将真实数据开辟到堆区,用指针指向它
}
~person()
{
if (m_age != null)
{
delete m_age;
m_age = null;
}
}
//重载赋值运算符
person& operator=(person &p)
{
//先判断p2是否有属性在堆区,如果有先释放干净,然后再深拷贝
if (m_age != null)
{
delete m_age;
m_age = null;
}
m_age = new int(*p.m_age);//深拷贝,指向新的空间
//要注意链式编程思想,重返的不应该是void要返回对象本身
return *this;
}
int *m_age;//指针,将数据开辟到堆区
};
void test01()
{
person p1(18);
person p2(20);
person p3(30);
p3=p2 = p1;//赋值操作,将p1的值赋给p2,在构造函数的应用上正常,但是在析构函数释放堆区空间时,会报错
//因为在p2=p1时,会将p1的所有数据都放到p2上,会指向同一个地址空间,这样的话就会释放两次内存
//解决方案,利用深拷贝解决浅拷贝带来的问题
//p2=p1时不要让p2也指向同一块空间,而是建立一个新的空间
cout << "p1的年龄为: " <<*p1.m_age << endl;//加*是进行解引用操作
cout << "p2的年龄为: " << *p2.m_age << endl;
cout << "p3的年龄为: " << *p3.m_age << endl;
}
int main()
{
test01();
/*int a = 10;
int b = 20;
int c = 30;
c = b = a;
cout << "a= " << a << endl;
cout << "b= " << b << endl;
cout << "c= " << c << endl;*/
system("pause");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构