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

posted @   小小是  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示