类与对象(2)---类的6个默认成员函数
1.类的6个默认成员函数
任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
2.构造函数
2.1构造函数特性
构造函数的主要任务是初始化对象。
它有如下特征:
1. 函数名与类名相同。
2. 无返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。
class Date {public://1.无缺省// (1)无参构造函数Date(){}// 2.带参构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}//eg:Date d1();*1*函数重载的语法支持;*2*编译器会存在歧义,认为其是函数声明/*//2.全缺省如果是全缺省的构造函数,只Date d1;都会存在歧义Date(){}Date(int year = 2022, int month = 6, int day = 4){_year = year;_month = month;_day = day;}*/private:int _year;int _month;int _day; };void TestDate() {Date d1; // 调用无参构造函数Date d2(2015, 1, 1); // 调用带参的构造函数// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明// 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象// warning C4930: “Date d3(void)”Date d3();//错误 }
5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
6.编译器生成的默认构造函数的作用:
C++把类型分成内置类型(基本类型)和自定义类型。
内置类型/基本类型:语言本身定义的基础类型,包括 int / char / double 等等。
自定义类型:用 class / struct 等等定义的类型。
注意:
我们不写,编译器会默认生成的构造函数,内置类型不做处理,自定义类型会去调用它的默认构造函数。
有些编译器也会处理,但是那是个性化行为,并不是所有的编译器都会处理。
注意:C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在
类中声明时可以给默认值。class Time { public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}private:int _hour;int _minute;int _second; };class Date { private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t; };int main() {Date d;//利用监视可查看return 0; }
7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,默认构造函数只能有一个。
注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为
是默认构造函数。所以,
(1)一般情况下,有内置类型成员,就需要自己写构造函数,不能用编译器自己生成的。
(2)全部都是自定义类型成员,可以考虑让编译器自己生成。
结论:
1.一般情况下,构造函数都需要我们自己写。
2.以下情况可用自动生成的默认构造:
a.内置类型成员都有缺省值,且初始化符合我们的要求。
b.全是自定义类型的构造,且这些类型都定义默认构造。
2.2代码仓库
gitee/jimmywang16/learn_1/class_object1112/构造函数
3.析构函数
3.1析构函数特性
1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。5.编译器
生成的默认析构函数,对自定类型成员调用它的析构函数。6.如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
4.拷贝构造函数
4.1拷贝构造函数特征
1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
Date(const Date& d) {cout << "use Date(const Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day; }
3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了。
总结:
C++内置类型直接拷贝,自定义类型传参必须调用拷贝构造完成拷贝 。
5. 拷贝构造函数典型调用场景:
使用已存在对象创建新对象;
函数参数类型为类类型对象;
函数返回值类型为类类型对象;class Date { public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){cout << "use Date(const Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;}private:int _year;int _month;int _day; };int main() {Date d1(2024, 2, 26);Date d2(d1);return 0; }
5.赋值运算符重载
5.1.运算符重载
class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}bool operator<(const Date& x){if (_year < x._year){return false;}else if (_year == x._year && _month < x._month){return false;}else if (_year == x._year && _month == x._month && _day < x._day){return true;}return false;}
private:int _year;int _month;int _day;
};
int main()
{d1 < d2; //等价于下方d1.operator<(d2);return 0;
}
私有怎么办?——写到类的内部:
bool operator<(const Date& x)
{if (_year < x._year){return false;}else if (_year == x._year && _month < x._month){return false;}else if (_year == x._year && _month == x._month && _day < x._day){return true;}return false;
}
5.2赋值运算符重载
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 ;
};
******************重点区分******************
5.3前置++和后置++重载
5.4代码仓库
gitee/jimmywang16/learn_1/learn1113/赋值运算符重载及其相关
5.5 cout,cin
运算符重载是让自定义类型支持运算符;
两个运算符重载构成函数重载。
6.const成员
6.1用法
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数
隐含的this指针(*this),表明在该成员函数中不能对类的任何成员进行修改(不能对this指向的内容进行修改,+、-、>、<、==、... 需加const)。
权限的放大
本质:const Date* const this
this本身不能被修改,this指向的内容也不能被修改。
注意:
const加在——不需要修改——对象成员变量的函数。
class Date
{
public://...bool operator<(const Date& x) const;bool operator==(const Date& x) const;bool operator<=(const Date& x) const;bool operator>(const Date& x) const;bool operator>=(const Date& x) const;bool operator!=(const Date& x) const;static int Getmonthdays(int year, int month);Date& operator+=(int days);Date operator+(int days) const;Date& operator++();Date operator++(int);Date& operator-=(int days);Date operator-(int days) const;Date& operator--();Date operator--(int);//...int operator-(const Date& d) const;void Print() const // const加在不需要修改——对象成员变量的函数{cout << _year << " / " << _month << " / " << _day << endl;}
private://...
}
6.2易混淆
6.3代码仓库
learn1113/运算符重载、Date日期类和const成员
7.取地址及const取地址操作符重载
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
class Date { public :Date* operator&(){return this ;}const Date* operator&()const{return this ;} private :int _year ; // 年int _month ; // 月int _day ; // 日 };
这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需
要重载,比如想让别人获取到指定的内容!