淘宝客网站做的好的,开发公司工作总结,在网站底部给网站地图做链接,seo入口前言#xff1a;本文介绍类和对象中的一些比较重要的知识点#xff0c;为以后的继续学习打好基础。 目录
拷贝构造
拷贝构造的特征#xff1a;
自定义类型的传值传参
自定义类型在函数中的传值返回
如果返回值时自定义的引用呢#xff1f;
在什么情况下使用呢#… 前言本文介绍类和对象中的一些比较重要的知识点为以后的继续学习打好基础。 目录
拷贝构造
拷贝构造的特征
自定义类型的传值传参
自定义类型在函数中的传值返回
如果返回值时自定义的引用呢
在什么情况下使用呢
拷贝构造中的浅拷贝问题 编辑
为什么会释放两次呢
那么什么情况下需要深拷贝
运算符重载
运算符重载的基本语法
类中运算符重载函数的调用的两种方法
运算符重载与函数重载
运算符重载的特征
运算符重载的价值
如果将运算符重载成全局函数就无法访问类中的私有成员了。
解决方法
赋值运算符
调用拷贝构造与调用赋值重载的区别 拷贝构造 拷贝构造是一种特殊的构造函数 拷贝构造的特征
1.是构造函数的重载
2.参数只有一个并且只能是引用
3.拷贝构造可以不显示写编译器会自动生成默认构造。 浅拷贝值拷贝就是一个字节一个字节的拷贝。
编译器自动生成的默认拷贝的特点对内置类型的成员浅拷贝值拷贝对自定义类型的成员拷贝需要调用其拷贝构造 #include iostream
using namespace std;
class Date
{
public:Date(int year,int month,int day){_year year;_month month;_day day;}//拷贝构造Date(Date d){cout 拷贝构造 endl;_year d._year;_month d._month;_day d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024,6,10);Date d2(d1);//拷贝构造Date d3 d2;//拷贝构造return 0;
} 自定义类型的传值传参
#include iostream
using namespace std;
class Date
{
public:int GetYear(){return _year;}int GetMonth(){return _month;}int GetDay(){return _day;}Date(int year,int month,int day){_year year;_month month;_day day;}Date(Date d){cout 拷贝构造 endl;_year d._year;_month d._month;_day d._day;}
private:int _year;int _month;int _day;
};void f(Date d)
{cout d.GetYear() d.GetMonth() d.GetDay() endl;
}
int main()
{Date d1(2024,6,10);Date d2(d1);Date d3 d2;f(d1);return 0;
}
以上代码的运行结果 在给f函数传值传参时调用了一次拷贝构造。
结论自定义类型在进行传值传参时会进行拷贝构造。 如果拷贝构造的参数是自定义类型而不是自定义的引用那么就会出现无穷递归调用。 自定义类型在函数中的传值返回
下面有一段代码以这段代码为例讲一下该问题。
#include iostream
using namespace std;class Date
{public:Date(int year, int month, int day){_year year;_month month;_day day;}
private:int _year;int _month;int _day;
};Date f(Date d)
{return d;
}int main()
{Date d1(2024, 6, 10);Date d2 f(d1);return 0;
} 结论如果返回值是自定义类型那么返回时就会进行拷贝构造创建临时对象再将临时对象赋值给正在创建的类。
用一段错误代码解释上面的结论
Date f(Date d)
{return d;
}int main()
{Date d1(2024, 6, 10);Date d2 f(d1);return 0;
} 上述错误代码的报错 原因是因为临时对象具有常性用d2来引用临时对象是会出现权限放大的问题所以验证了上述的结论如果加上const权限平移报错就会消失。 而编译器为了提高效率往往会直接将其优化为一次拷贝构造。 如果返回值时自定义的引用呢
Date f()
{Date d1(2023, 1, 2);return d1;
}int main()
{Date d1 f();return 0;
} 因为d1 实在函数中定义的对象出了函数的作用域就会销毁。
从栈帧的角度来理解引用的本质是指针f函数被销毁了main函数中的d1仍指向f中的d1的那块已被销毁的空间 自定义类型的引用返回存在风险 在什么情况下使用呢
出了函数的作用域生命周期没到不构析对象还在那么就可以用引用 返回
出了函数的作用域生命周期到了析构对象不存在那么就只能用传值返回 拷贝构造中的浅拷贝问题
以下代码存在浅拷贝问题
#include stdlib.h
#include iostream
using namespace std;
class Stack
{
public:Stack(int capacity 4){cout Stack() endl;_arr (int*)malloc(sizeof(int) * capacity);_capacity capacity;_top 0;}~Stack(){cout ~Stack()endl;free(_arr);_capacity 0;_top 0;}
private:int* _arr;int _top;int _capacity;
};int main()
{Stack st1(4);Stack st2(st1);return 0;
}
程序崩溃 该代码的问题就在于对一块开辟的空间释放两次。
为什么会释放两次呢
因为没有显示写拷贝构造函数所以用的是编译器自动生成的拷贝构造函数浅拷贝所以在拷贝构造st2时使st2中_arr指向的空间与st1中的一样最后分别调用析构函数时就造成了对用一块开辟的空间释放两次。 解决方案就是深拷贝 Stack(Stack st){_arr (int*)malloc(sizeof(int) * st._capacity);//深拷贝_capacity st._capacity;_top st._top;}
那么什么情况下需要深拷贝
总结
1.如果没有管理资源就不显示写拷贝构造用默认拷贝构造就可以
2.都是自定义的成员内置类型内置类型不指向资源也用默认拷贝如果自定义类型的成员的内置类型指向资源那么在该自定义类型中显示写拷贝构造
3.一般不需要写析构函数就需要写构造函数
4.内部有指针或一些值指向资源显示写析构释放通常需要写拷贝构造来完成深拷贝 运算符重载 运算符重载的基本语法
返回值类型 operater运算符参数列表
operator是关键字operator和运算符一起构成函数名。 类中运算符重载函数的调用的两种方法 //在类中实现的运算符重载实现日期与天数的相加Date operator(int day){_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 12){_month 1;_year;}}return *this;} //已经在类中写了一个加号重载的函数Date d1(2024, 6, 10);d1 100;//第一种调用方法d1.operator(100);//第二种调用方法 运算符重载与函数重载
运算符重载和函数重载没有关系是两回事而多个相同的运算符的重载是函数重载。
比如(流插入)可以自动识别内置类型的原因就是对进行重载构成了函数重载。 运算符重载的特征
1.不能通过其他符号重载
2.必须有一个类类型的参数
3.含义不能改变这里是建议比如重载的的含义是将两个数相加而你写的含义是相减
4.一般参数比运算符操纵的操作数的数目少1因为在参数列表中有隐含的this指针
5. .* :: sizeof ?: . 这五个操作符不能被重载.*是用于类成员函数指针的访问
如果想了解函数指针到底需不需要解引用类成员函数呢_函数指针需要解引用吗-CSDN博客 运算符重载的价值
运算符重载是运算符不仅限于操纵内置类型的数据可以实现类与类之间或类与内置类型直间的运算可以增强代码的可读性。 一个使用运算符重载的例子
#include iostream
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}//得到当前月份的天数int GetMonthDay(int year, int month){int month_day[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if(month2((year%40year%100!0)||year%4000))return 29;return month_day[month];}//重载运算符实现日期与天数的相加Date operator(int day){_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 12){_month 1;_year;}}return *this;}void Print(){cout _year _month _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 6, 10);Date d2 d1 100;d2.Print();return 0;
}
上述代码中的的重载是在类中实现的,或在类中声明在类外实现。 如果将运算符重载成全局函数就无法访问类中的私有成员了。
解决方法
1.在类中实现成员的Get获取成员和Set重新给成员赋值的接口
2.将全局函数设为该类的友元
3.重载为成员函数可以访问类的成员但函数不在是全局函数
这些方法比较建议第二种。 以下的代码是通过友元来实现全局减号的运算符重载
#include iostream
using namespace std;
class Date
{//友元就是在函数前加上一个关键字friend并在相应的类中声明friend Date operator-(Date d,int day);
public:Date(int year, int month, int day){_year year;_month month;_day day;}int GetMonthDay(int year, int month){int month_day[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 };if(month2((year%40year%100!0)||year%4000))return 29;return month_day[month];}Date operator(int day){_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 12){_month 1;_year;}}return *this;}void Print(){cout _year _month _day endl;}
private:int _year;int _month;int _day;
};//全局函数减号的重载
Date operator-(Date d,int day)
{d._day - day;while (d._day 0){if (d._month 1){d._month 12;d._year--;}else{d._month--;}d._day d.GetMonthDay(d._year, d._month);}return d;
} 赋值运算符 赋值运算符重载也是6个默认成员函数之一。 调用拷贝构造与调用赋值重载的区别 Date d1(2024, 6, 10);Date d2 d1;//拷贝构造Date d3(d1);//拷贝构造Date d4(2024, 2, 11);d4 d1;//赋值重载
注意上面代码中两个等号的调用方式容易混但最后这两个有本质的区别。 结语希望本文能够让你有所收获 。