一、总体介绍
首先,当你定义出一个空类时(class Date {}),你会觉得空类里面真的是空的吗?可当你进行一些使用时,如取地址,为什么还是可以正常使用呢?我猜你可能会说,因为这是C++默认就实现好了的啊,没错,在用户没有显式实现时,编译器会自动生成成员函数,这样的函数,称之为默认成员函数。那么既然如此,我们来看看成员函数有哪些,并如何显式实现:
二、初始化与清理(2个)
1.构造函数
构造函数主要完成的是初始化的工作,避免如C语言中使用某些变量时出现未初始化的警告和错误,显式的实现如下:
class Date
{
public:
// 1.无参构造函数
Date()
{}
// 2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
调用如下:
从上面的过程观察,可以发现以下几点特征:
2.析构函数
析构函数的功能与构造函数相反,在对象销毁时,对象会自动调用析构函数,完成对象中资源的清理,显式实现如下:
class Date
{
public:
~Date()//析构函数
{
delete test;
test=NULL:
_year = 0;
_month = 0;
_day = 0;
}
private:
int _year;
int _month;
int _day;
int* test;
};
调用如下,不是很规范,看看即可:
如此,从上可总结特征:
(1). 析构函数名是在类名前加上字符“~”
(2). 无参数无返回值类型。
三、拷贝复制(2个)
1. 拷贝构造函数
既然这个函数有着构造的名字,那么差不多就和初始化有关,不过这个“初始化”是为了初始化一个与输入参数相同的类型出来,简单来说,就是copy。但要记住默认拷贝构造函数的浅拷贝只是简单的复制值,想要实现深拷贝,需要自己定义。显式实现如下:
class Date
{
public:
//Date(const Date d)//错误写法
Date(const Date& d)//正确写法
{
_year = d._year;
_month = d._month;
_day = d._day;
int* _test=new int[10];
memcpy(_test,d._test,10*sizeof(int);
}
private:
int _year;
int _month;
int _day;
int _test[10];
};
调用如下:
如上观察,可以看到,拷贝构造函数是构造函数的一种重载,但也有一些特征,就是拷贝构造函数的参数有且只有一个,且必须是类 类型对象的引用,不然使用传值方式会引发无穷递归。
发生无穷递归的原因说起来很简单,就是使用传值传参时,形参会去调用 ”拷贝构造函数“ 拷贝实参,然后就没了,就无穷递归下去了。听起来是不是挺懵逼的?hhhh,那么就举一个简单的说法,就是你要启动一个工具,但这个工具要首先调用另一个工具才能用,可是调用的工具又是都一样的,那么就无穷的调用下去了。
2.赋值运算符重载
该函数是C++为了增强代码的可读性而引入的,具有特殊的函数名和规则:
class Date
{
public:
//等于=
Date& operator=(const Date& d)
{
this->_year = d._year;
this->_month = d._month;
this->_day = d._day;
return *this;
}
// 前置++
Date& operator++()
{
*this+= 1;
return *this;
}
//后置++
Date operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
// 后置--
Date operator--(int)
{
Date tmp(*this);
*this-=1;
return tmp;
}
// 前置--
Date& operator--()
{
*this-=1;
return *this;
}
private:
int _year;
int _month;
int _day;
int _test[10];
};
调用如下:
观察上面过程,可以得出以下特征:
(1)参数类型:const T&,传递引用可以提高传参
(2)返回值类型:一般使用T&,返回引用可以提高返回的效率,有返回值目的是为了支 持连续赋值
(3) 检测是否自己给自己赋值
(4) 返回*this :保证可以连续赋值
三、取地址重载(2个)
1&2.取地址操作符重载、const取地址操作符重载
这两个函数其实差别不大,并且一般情况下编译器会自动生成,不用自己定义,除非想得到某些特定的内容才自己定义,显式实现如下:
class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&()const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
调用如下:
四、总结
这6个函数中前4个函数较为重要,一般使用时注意文中提到的点即可。但是为了本文的简洁可读性,有些细节问题没有去详细展开,如赋值运算符重载还细分为运算符重载,赋值运算符重载,若是各位还想继续了解,还需自行查找。