公司请人做的网站 域名属于谁,网站建设公司郴州,外贸三种语言网站建设,红色系网站文章目录 前言一、拷贝构造函数1. 概念2. 特征3. 编译器生成默认拷贝构造函数4. 拷贝构造函数典型使用场景 二、运算符重载函数三、赋值运算符重载函数1. 赋值运算符重载格式2. 赋值运算符只能重载成类的成员函数不能重载成全局函数3.编译器生成一个默认赋值运算符重载4. 运算符… 文章目录 前言一、拷贝构造函数1. 概念2. 特征3. 编译器生成默认拷贝构造函数4. 拷贝构造函数典型使用场景 二、运算符重载函数三、赋值运算符重载函数1. 赋值运算符重载格式2. 赋值运算符只能重载成类的成员函数不能重载成全局函数3.编译器生成一个默认赋值运算符重载4. 运算符重载函数和赋值运算符重载函数的调用 四、前置和后置重载总结 前言
C拷贝构造函数、运算符重载函数、赋值运算符重载函数、前置和后置重载等的介绍 一、拷贝构造函数
在实际运用中我们有时候需要操作一个实例化好的类但是又不想改变这个类这时候我们就需要拷贝构造函数。
1. 概念
拷贝构造函数只有单个形参该形参是对本类类型对象的引用(一般常用const修饰)在用已存在的类类型对象创建新对象时由编译器自动调用。
2. 特征
拷贝构造函数也是特殊的成员函数其特征如下
拷贝构造函数是构造函数的一个重载形式。拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错因为会引发无穷递归调用。
拷贝构造函数是构造函数的一个重载形式所以拷贝构造函数的函数名与类名相同参数与构造函数不同无返回值。
如下图 采用传值调用会引发无穷递归编译器强制检查报错。 应该采用类类型对象的引用如下
#include iostream
using namespace std;class Date
{
public:Date(int year 1945, int month 8, int day 15){_year year;_month month;_day day;}Date(const Date d){_year d._year;_month d._month;_day d._day;}~Date(){_year 0;_month 0;_day 0;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 6, 22);Date d2(d1);return 0;
}3. 编译器生成默认拷贝构造函数
若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。
简单来说就是不显示定义编译器默认生成一个构造函数
对于内置类型会进行值拷贝浅拷贝。对于自定义类型会调用它的拷贝构造函数。
#include iostream
using namespace std;class Date
{
public:Date(int year 1945, int month 8, int day 15){_year year;_month month;_day day;}~Date(){_year 0;_month 0;_day 0;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2023, 9, 1);Date d2(d1);return 0;
}编译器默认生成的拷贝构造函数是值拷贝浅拷贝但是有些情况下我们需要深拷贝。比如 对一个栈我们不能直接浅拷贝程序会崩溃。原因如下
浅拷贝会将一个栈动态申请的空间的地址拷贝个另一个栈的指针所以两个栈对象的指针指向同一块空间析构函数会对同一块空间释放两次程序会崩溃。
#include iostream
using namespace std;class Stack
{
public:Stack(int capacity 4){_a (int*)malloc(sizeof(int) * capacity);if (nullptr _a){perror(Stack malloc);return;}_top 0;_capacity capacity;}void Push(int x){// 增容_a[_top] x;_top;}~Stack(){if (_top){free(_a);_a nullptr;_top 0;_capacity 0;}}
private:int* _a;int _top;int _capacity;
};int main()
{Stack st1(10);st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);Stack st2(st1);return 0;
}所以这种Stack的类对象我们应该自己显示定义拷贝构造函数。
#include iostream
using namespace std;class Stack
{
public:Stack(int capacity 4){_a (int*)malloc(sizeof(int) * capacity);if (nullptr _a){perror(Stack malloc);return;}_top 0;_capacity capacity;}Stack(const Stack st){_a (int*)malloc(sizeof(int) * st._capacity);if (nullptr _a){perror(Stack malloc);return;}memcpy(_a, st._a, sizeof(int) * st._top);_top st._top;_capacity st._capacity;}void Push(int x){// 增容_a[_top] x;_top;}~Stack(){if (_top){free(_a);_a nullptr;_top 0;_capacity 0;}}
private:int* _a;int _top;int _capacity;
};int main()
{Stack st1(10);st1.Push(1);st1.Push(2);st1.Push(3);st1.Push(4);Stack st2(st1);return 0;
}注意类中如果没有涉及资源申请时拷贝构造函数是否写都可以一旦涉及到资源申请时则拷贝构造函数是一定要写的否则就是浅拷贝。
4. 拷贝构造函数典型使用场景
使用已存在对象创建新对象函数参数类型为类类型对象函数返回值类型为类类型对象
二、运算符重载函数
在介绍运算符重载之前先来看看运算符重载和函数重载的比较
函数重载和运算符重载都用了“重载”一词但是两者重载没有关系函数重载是为了函数名相同函数参数不同的函数可以同时存在运算符重载是为了自定义类型的数据也可以像内置类型一样使用运算符进行比较或赋值等
C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。函数名字为关键字operator后面接需要重载的运算符符号。 函数原型返回值类型 operator操作符(参数列表)
注意
不能通过连接其他符号来创建新的操作符比如operator重载操作符必须有一个类类型参数用于内置类型的运算符其含义不能改变例如内置的整型不 能改变其含义作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐藏的this.*、 ::、 sizeof 、?: . 注意以上5个运算符不能重载**
#include iostream
using namespace std;class Date
{
public:Date(int year 1945, int month 8, int day 15){_year year;_month month;_day day;}~Date(){_year 0;_month 0;_day 0;}
//private:int _year;int _month;int _day;
};bool operator(const Date x1, const Date x2)
{if (x1._year x2._year){return true;}else if (x1._year x2._year x1._month x2._month){return true;}else if (x1._year x2._year x1._month x2._month x1._day x2._day){return true;}else{return false;}
}bool operator(const Date x1, const Date x2)
{if (x1._year x2._year){return true;}else if (x1._year x2._year x1._month x2._month){return true;}else if (x1._year x2._year x1._month x2._month x1._day x2._day){return true;}else{return false;}
}int main()
{Date d1(1945, 8, 15);Date d2(1949, 10, 1);cout operator(d1, d2) endl;cout (d1 d2) endl;cout operator(d1, d2) endl;cout (d1 d2) endl;return 0;
}使用运算符重载时调用运算符重载函数也可以直接使用运算符比较。 cout operator(d1, d2) endl;cout (d1 d2) endl;cout operator(d1, d2) endl;cout (d1 d2) endl;一般建议直接使用运算符比较。
上述运算符重载到了全局中运算符重载也可以重载到类中。
#include iostream
using namespace std;class Date
{
public:Date(int year 1945, int month 8, int day 15){_year year;_month month;_day day;}bool operator(const Date x2){if (_year x2._year){return true;}else if (_year x2._year _month x2._month){return true;}else if (_year x2._year _month x2._month _day x2._day){return true;}else{return false;}}~Date(){_year 0;_month 0;_day 0;}
private:int _year;int _month;int _day;
};int main()
{Date d1(1945, 8, 15);Date d2(1949, 10, 1);cout d1.operator(d2) endl;cout (d1 d2) endl;return 0;
}三、赋值运算符重载函数
1. 赋值运算符重载格式
参数类型const T传递引用可以提高传参效率返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值检测是否自己给自己赋值返回*this 要复合连续赋值的含义
#include iostream
using namespace std;class Date
{
public:Date(int year 1945, int month 8, int day 15){_year year;_month month;_day day;}Date operator(const Date d){if (this ! d){_year d._year;_month d._month;_day d._day;}return *this;}~Date(){_year 0;_month 0;_day 0;}
private:int _year;int _month;int _day;
};int main()
{Date d1(1945, 8, 15);Date d2(1949, 10, 1);//d2.operator(d1);d2 d1;return 0;
}赋值运算符可以选择调用赋值运算符重载函数也可以直接使用赋值运算符一般建议直接使用赋值运算符。 d2.operator(d1);d2 d1;2. 赋值运算符只能重载成类的成员函数不能重载成全局函数 原因赋值运算符如果不显式实现编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值运算符重载只能是类的成员函数。 class Date
{
public:Date(int year 1945, int month 8, int day 15){_year year;_month month;_day day;}~Date(){_year 0;_month 0;_day 0;}
//private:int _year;int _month;int _day;
};Date operator(Date left, const Date right)
{left._year right._year;left._month right._month;left._day right._day;return left;
}3.编译器生成一个默认赋值运算符重载
用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。
注意 内置类型成员变量是直接赋值的 而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。 注意如果类中未涉及到资源管理赋值运算符是否实现都可以一旦涉及到资源管理则必须要实现。
4. 运算符重载函数和赋值运算符重载函数的调用
内置类型使用运算符进行操作直接转换成指令进行操作。自定义类型若直接使用运算符操作会调用对应的运算符重载函数。
四、前置和后置重载
#include iostream
using namespace std;class Date
{
public:Date(int year 1328, int month 1, int day 4){_year year;_month month;_day day;}// 前置Date operator(){_day 1;return *this;}// 后置Date operator(int){Date tmp(*this);_day 1;return tmp;}
private:int _year;int _month;int _day;
};int main()
{Date d;Date d1(1949, 10, 1);d d1; // d: 1949 10 1 d1: 1949 10 2d d1; // d: 1949 10 3 d1: 1949 10 3return 0;
}前置 前置返回1之后的结果 注意this指向的对象函数结束后不会销毁故以引用方式返回提高效率。后置 前置和后置都是一元运算符为了让前置与后置形成能正确重载 C规定后置重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器自动传递 注意后置是先使用后1因此需要返回1之前的旧值故需在实现时需要先将this保存一份然后给this1而temp是临时对象因此只能以值的方式返回不能返回引用 总结
C拷贝构造函数、运算符重载函数、赋值运算符重载函数、前置和后置重载等的介绍。