目录
一、构造函数
1.概念
2.特性
二、拷贝构造函数
1.概念
2.特性
3.注意事项
编辑
三、赋值运算符重载
1.运算符重载
(1)概念
(2)定义和使用
(3)注意事项
2.赋值运算符重载
(1)概念
(2) 赋值运算符重载格式
(3)注意事项
构造函数:属于六大特殊成员函数,名字与域名相同,创建类型对象时有编译器自动调用,以保证每个数据成员都有一个合适的初值。构造函数在类型对象生命周期类仅仅调用一次(不能反复初始化)
#include
using namespace std;
class Date
{
public:
//1. 函数名与类名相同,无参调用
Date()
{
_year = 1;
_month=1;
_day=1;
}
//2.函数名与类名相同,带参调用
Date(int year,int month,int day)
{
_year = 1;
_month = 1;
_day = 1;
}
void Display()
{
cout<< _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1();//调用 1
Date d2(2022,8,5);//调用 2
return 0;
}
1.和2.可以结合来写
定义了一个类--Date
class Date
{
公有
public:
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
私有
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;//实例化出一个对象,d1
d1.SetDate(2018, 5, 1);//手动初始化第一次
d1.Display();
Date d2;//实例化出一个对象,d2
d2.SetDate(2018, 7, 1);//手动初始化第二次
d2.Display();
return 0;
}
注意:
1.构造函数其实“名不符实”。构造函数的主要任务是初始化对象而非开空间创建对象
2.任何一个类的默认构造函数有三个:全缺省,无参,编译器自动生成,但是三个只能有一个存在。
3.任何一个类的默认构造参数都是可以不用参数就直接调用。
4.不能通过对象调用构造函数,(这样是错误的: d1.Date() )
创建对象时,可否创建一个与已存在对象一某一样的新对象呢?拷贝构造函数: 只有单个形参 ,该形参是对本 类类型对象的引用 (一般常用const修饰 ) ,在用 已存在的类类型对象创建新对象时由编译器自动调用 。
拷贝构造函数也是特殊的成员函数,其 特征 如下:1. 拷贝构造函数 是构造函数的一个重载形式 。2. 拷贝构造函数的 参数只有一个 且 必须是类类型对象的引用 ,使用 传值方式编译器直接报错 ,因为会引发无穷递归调用。
#include
using namespace std;
class Date
{
public:
// 构造会频繁调用,所以直接放在类里面定义作为inline
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//拷贝构造函数
Date(const Date& d)//必须传引用
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2022, 8, 21);
Date d2(10);
Date d3(d1);
return 0;
}
1.拷贝构造函数必须使用应用传参,不然在Date d2 (d1)会出现无穷递归(反复调用拷贝构造函数)
2.使用浅拷贝时候要注意系统会不会析构两次
关于两次析构可以通过这个错误案例来观察
//栈
class Stack
{
public:
//构造
Stack(int capacity = 4)
{
_a = (int*)malloc(sizeof(int));
if (_a == nullptr)
{
cout << "malloc fail" << endl;
exit(-1);
}
_top = 0;
_capacity = capacity;
}
//拷贝构造
//...使用系统默认生成的
private:
int* _a;
int _top;
int _capacity;
};
int main()
{
Stack st1(5);
Stack st2(st1);
return 0;
}
出现上面这个错误提示的原因是 st1,st2指向了同一块空间,会造成析构了两次
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
// 全局的operator==
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//private:
int _year;
int _month;
int _day;
};
这里会发现运算符重载成全局的就需要成员变量是公有的,那么问题来了,封装性如何保证?这里其实可以用我们后面学习的友元解决,或者干脆重载成成员函数。
1.不能通过连接其他符号来创建新的操作符:比如operator@2.重载操作符必须有一个类类型参数3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义4.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this5..* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。
赋值运算符重载是对两个已经存在的自定义类型对象的赋值
class Date
{
public :
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date (const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year ;
int _month ;
int _day ;
};
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
// 赋值运算符重载成全局函数,注意重载成全局函数时没有this指针了,需要给两个参数
Date& operator=(Date& left, const Date& right) {
if (&left != &right)
{
left._year = right._year;
left._month = right._month;
left._day = right._day;
}
return left; }
// 编译失败:
// error C2801: “operator =”必须是非静态成员
原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的 赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的 成员函数。
class Time
{
public:
Time()
{
_hour = 1;
_minute = 1;
_second = 1;
}
Time& operator=(const Time& t)
{
if (this != &t)
{
_hour = t._hour;
_minute = t._minute;
_second = t._second;
}
return *this;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
// 基本类型(内置类型)
int _year = 1970;
int _month = 1;
int _day = 1;
// 自定义类型
Time _t;
};
int main()
{
Date d1;
Date d2;
d1 = d2;
return 0;
}