c++中类共有六个默认成员函数
,每个类都有默认的成员函数,空类也是如此。主要完成三个任务:1,初始化和清理 2,拷贝复制 3,取地址重载。为什么会有默认构造函数的存在呢?必有其存在的道理,在c语言阶段,我们定义一个栈等数据结构,会自己写初始化,清理的函数,如果忘记了清理,会有内存泄漏
的麻烦。所以何必一直要自己来调用呢,在类中我们直接让它自己调用即可,方便了不少。本文,主要讲默认成员函数的使用规则和一些注意点。用日期类举例子,所以将其给出来,不是劝退哈,讲完后会发现其简单的很。
class Date
{
friend ostream& operator <<(ostream& out, const Date& d);
public:
Date& operator=(const Date &d);
Date(int year = 1, int month = 1, int day = 1);//构造函数
void Print()const;
int GetMonthDay(int year, int month)const;
Date(const Date &d);
bool operator>(const Date& d)const;
bool operator<(const Date& d)const;
bool operator>=(const Date& d)const;
bool operator<=(const Date& d)const;
bool operator==(const Date& d)const;
bool operator!=(const Date& d)const;
Date& operator+=(int day);
Date operator+(int day)const;
Date& operator-=(int day);
Date operator-(int day)const;
Date& operator++();
Date operator++(int);//后置++
Date& operator--();
Date operator--(int);
int operator-(const Date& d)const;
void PrintWeekDay() const;
private:
int _year;
int _month;
int _day;
};
一,构造函数
构造函数,函数名就是类名
。
所谓默认构造函数,就是我们不传参数,自动会初始化成员变量;我们不去主动的声明构造函数,就会直接调用系统默认生成的;如果我们自己声明以及定义了一个构造函数那么就有两种情况:
1.
Date();
Date(int year = 1, int month = 1, int day = 1);
这就是默认构造函数的两种形式:无参的
,全缺省的
。这是满足默认构造函数的,无需我们传参,就会直接调用其来初始化成员变量。
2.
当然,也有需要传参的构造函数,这是依据个人需求来的。但是不会你定义一个类就会自动的初始化,这需要传参来初始化了。
Date(int year,int month,int day);//不缺省
Date(int year, int month = 1, int day = 1);//半缺省
但是
,系统默认生成的构造函数和我们自己动手写的默认构造函数有区别嘛?答案是:当然有。
系统默认生成的构造函数不会对内置类型做处理,只会操作自定义类型。内置类型就是int,double,char等系统给定的类型,自定义类型就比如自己定义的类,系统会调用这个类自身的默认构造函数。
class Date
{
private:
int _year;
int _month;
int _day;
}
日期类系统自带的构造函数不会做任何的处理。我们如果想初始化内置类型的成员变量就必须得自己写构造函数。
class A
{
private:
Date _a;
Date _b;
}
像这种类,我们是不需要写构造函数的,默认的就够用。因为默认的构造函数会直接调用Date类的默认构造函数来初始化,_a,_b。这俩个自定义类型成员变量。至于Date类有没有默认构造函数,这我们不需要关心,一码事归一码事。
我们来写一个日期类的构造函数:
Date::Date(int year=1,int month=1;int day=1)
{
_year = year;
_month = month;
_day = day;
if (!(_year >= 0 && (month > 0 && month<13) && (day <= GetMonthDay(year, month) && day>0)))
{
cout << "日期非法-->";
}
二,析构函数
~类名
。那么何时会调用析构函数呢?在类的成员变量的生命周期结束时,会自动调用析构函数。同样有俩种情况:我们不自己写析构函数那么就会用系统默认的析构函数;如果写了就会用
自己写的析构函数。注意下面俩段代码,我们可以判断一下,哪个类用写析构函数,哪个不用写?
class A
{
private:
int _a;
}
class B
{
private:
int *b;
}
class C
{
private:
A c;
}
类A没有资源需要处理,所以不用写析构函数;类B需要自己动手写析构函数,如果不写,可能造成内存泄漏,野指针等问题;类C不用自己动手写,用默认的析构函数就行了。
系统默认的析构函数和构造函数一样,都不会对内置类型做处理,只操作自定义成员变量,会调用其本身的析构函数。
因为,日期类和类A一样,都没有资源需要处理,所以我写个类B的析构函数。
~B()
{
free(this->b);
}
这里大家可能会对this指针有问题,可以看此篇博文《this指针详解》。
三,拷贝构造
日期类不需要拷贝构造,系统自带的就足够了。但是也可以小写一波。
Date::Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
四,运算符重载
类
的类型参数。.*
, ::
, sizeof
, .
,?:
这五位老哥不能重载。写一个赋值重载,就是=
的重载。
Date& Date::operator=(const Date &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
return *this;
}
赋值重载,系统其实也有默认的赋值重载,默认的赋值重载干的事情和拷贝构造完全类似。
取地址操作符的重载,const修饰的取地址操作符重载
这个重载自己实现的较少,默认的重载就够了,但是如果想让别人取到特定的地址还是有必要自己实现的。
class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&()const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
}
这就是日期类取地址运算符的重载。
总结:类的默认成员函数有构造,析构,拷贝,赋值操作符重载,取地址操作符重载,const修饰的取地址操作符重载。灵活运用,默认的不够用,就自己写,根据需求来完成类的成员函数。