c++运算符重载与拷贝问题学习心得
运算符重载
加法运算符重载
调用本质和方法都在上面。
左移运算符重载
注意到输入流和输出流也可以看成一个类,和int其实没有什么差别,至于&,返回一个输出流的引用是因为该类只有一个,不能拷贝(我的理解目前是这样,估摸着不怎么精准,大家将就看哈)
递增运算符重载
这里注意后置++是一个死写法,记住就好了,int 只是一个占位符,为了通过参数的不同达到重载函数的目的
赋值运算符重载
这个通常会和地址挂钩,故而涉及到浅拷贝和深拷贝的问题,将与拷贝问题一起展示
可重载的运算符
不可重载的运算符
练习一下运算符重载吧~
题目如下:
有位同学不小心把写了一半的代码弄乱了,不仅丢失了一些代码,里面还被小精灵混入了大量不可见的魔国符号,请你帮他把代码梳理清楚,并将他的错误更正。
using namespace std; class Counter{ public: Counter(){value=0;}
Counter(int i){value=i;} friend Counter operator ++(Counter &); friend Counter operator (Counter c1,Counter c2); void display(){cout<<value<<endl;} private: unsigned value; }; Counter operator ++(Counter &p) { p.value++; return p; } Counter operator (Counter c1,Counter c2) { Counter temp; temp.value=c1.valuec2.value; return temp; } int main() { Counter ctr,ctr1; cin>>ctr;cin>>ctr1;ctr++; ctr2=ctrctr1; //ctr3.display(); return 0;}
【输入形式】
两个整数
【输出形式】
一个整数
【样例输入】
5 6
【样例输出】
36
解决代码示例
#include "iostream"
using namespace std;
class Counter
{
friend Counter operator++(Counter &p);//运用友元的知识
friend Counter operator *(Counter c1,Counter c2);
friend istream &operator>>(istream &cin,Counter &p);
public:
Counter()//构造函数
{
value=0;
}
void display(){cout<<value<<endl;}
private:
unsigned int value;
};
Counter operator++(Counter &p)
{
p.value++;
return p;
}
Counter operator *(Counter c1,Counter c2)
{
Counter temp;
temp.value=c1.value*c2.value;
return temp;
}
istream &operator>>(istream &cin,Counter &p)
{
cin>>p.value;
}
int main()
{
Counter ctr,ctr1,ctr2;
cin>>ctr;
cin>>ctr1;
++ctr;
ctr2=ctr*ctr1;
ctr2.display();
return 0;
}
怎么样,是不是掌握了呢~
拷贝问题
为什么会有拷贝问题
浅拷贝:
简单的赋值拷贝操作,地址也是一样的
深拷贝:
在堆区中重新申请空间,进行拷贝操作
浅拷贝带来的问题就是堆区的重复释放,解决方案便是自己实现拷贝构造函数
栈区的规则是先进后出
自动释放的内存是栈区的变量而不是堆区的
代码示例
#include <iostream>
#include <cstring>
using namespace std;
class Person
{
public :
string name;
int *p;
Person(){} //默认构造函数
Person(const Person &b) //深拷贝构造函数
{
name=b.name;
p=b.p;
p=new int [10];//给该对象也开辟一个内存
for(int i=0;i<10;i++)
{
p[i]=b.p[i];
}
}
Person & operator=(const Person &b) //重载赋值运算符
{
name=b.name;
p=b.p;
return *this;
}
};
int main()
{
Person j;
j.name="jz";
j.p=new int[10];//给j对象在堆区开辟了一块内存
for(int i=0;i<10;i++)
j.p[i]=i;
//Person y=j;
Person y;
y=j;
y.p[0]=200;
cout << j.p[0] << endl;
return 0;
}
示例2
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)
{
//编译器提供的是浅拷贝
// m_Age=p.m_Age;
//应该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
if(m_Age!=NULL)//this->m_Age!=NULL
{
delete m_Age;
m_Age=NULL;
}
m_Age= new int (*p.m_Age)//深拷贝
return *this;//返回对象本身
}
int *m_Age;
};
void test01()
{
Person p1(18);
cout<<"p1的年龄为: "<<p1.m_Age<<endl;
cout<<"p1的年龄为: "<<*p1.m_Age<<endl;
Person p2(20);
p2=p1;//赋值操作
cout<<"p2的年龄为: "<<p2.m_Age<<endl;
cout<<"p2的年龄为: "<<*p2.m_Age<<endl;
}
int main()
{
int a=10;
int b=20;
int c=30;
c=b=a;//输出全都是10;
}
默认构造函数小记
//注意: &读作at,在函数申明的时候是引用的意思,其他的时候才是取地址
class w
{
public:
int a,b;
w(){}//
w(int i_a,int i_b):a(i_a),b(i_b){}
w(int i_a,int i_b)
{
a=i_a;
b=i_b;
}
w(const w&w1)//有参普通构造
{
this->a=w1.a;
this->b=w1.b;
cout<<"构造"<<endl;
}
w&operator=( const w &w1)//重载赋值运算符
{
cout<<"赋值"<<endl;
this->a=w1.a;
this->b=w1.b;
return *this; //返回该类的值,例如 a=b,写在类A里面,this表示是类A的指针,指向该类本身的某一个实例化对象,*this表示a
// this表示运算符前面的那个操作数
}
};
int main()
{
w w1;
w1.a=100;
w1.b=100;
w w2;//调用第1个
w2=w1;//调用第3个
//w w3(w1); 初始化
w w3=w1;//调用第2个,与上面一个等价.
cout<<w2.a<<" "<<w2.b<<endl;
return 0;
}
作者小记
这是临近期末的学习笔记,今天耗时9小时才从0学会了这么一点点。可能有些零碎,大家也请多多包含。有什么不对或者更好的见解也欢迎留言呀。喜欢也可以关注我哦~学习路上会努力!