【C++自学笔记】类的六个默认成员函数

一、构造函数

构造函数是特殊的成员函数,需要注意的是,构造函数名称虽然叫构造函数,但是需要注意的是它并不是开辟空间创建对象,而是对对象进行初始化。如果类中没有显示定义构造函数,C++编译器会自动生成一个无参的构造函数,一旦用户显示定义编译器将不再生成。

class Date{
public:
    //无参的构造函数
    Date(){
    }
    //带参的构造函数
    Date(int year,int mouth,int day){
        _year = year;
        _mouth = mouth;
        _day = day;
    }
private:
    int _year;
    int _mouth;
    int _day;
};

构造函数的特征:

  1. 函数名与类名相同;
  2. 无返回值;
  3. 对象实例化时编译器自动调用对应的构造函数;
  4. 构造函数可以重载;

无参的构造函数和全缺省的构造函数都被称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、编译器默认生成的默认构造函数都可以被认为是默认构造函数。

例如下面的代码,有两个默认的构造函数,再编译过程中,编译器会报错。

class Date {
public:
	Date() {
		_year = 1900;
		_mouth = 1;
		_day = 1;
	}
	Date(int year = 1900,int mouth = 1,int day = 1) {
		_year = year;
		_mouth = mouth;
		_day = day;
	}
private:
	int _year;
	int _mouth;
	int _day;
};
int main() {
	Date d1;
	return 0;
}

那么问题来了,编译器默认生成的构造函数到底有什么用?

答案是:编译器生成默认的构造函数会对自定类型(是用class、struct、union自己定义的类型)成员调用;

class Time{
public:
    Time(){
        cout << "Time()" << endl;
        _hout = 0;
        _minute = 0;
        _second = 0;
    }
private:
    int _hour;
    int _minute;
    int _second;
};
class Date{
private:
    //基本类型(内置类型)
    int _year;
    int _mouth;
    int _day;
    //自定义类型
    Time _t;
};

二、析构函数

析构函数:与构造函数的功能相反,构造函数不是完成对象的销毁,局部对象的销毁工作是由编译器完成的,而对象在销毁时会自动调用析构函数,完成类的一些清理工作。

typedef int DataType;
class SeqList{
public :
    SeqList (int capacity = 10){
        _pData = (DataType*)malloc(capacity * sizeof(DataType));
        assert(_pData);
        _size = 0;
        _capacity = capacity;
    }
    ~SeqList(){
        if (_pData){
            free(_pData ); // 释放堆上的空间
            _pData = NULL; // 将指针置为空
            _capacity = 0;
            _size = 0;
        }
    }
private :
    int* _pData ;
    size_t _size;
    size_t _capacity;
};

析构函数的特性:

  1. 析构函数名是在类名前面加上字符 ~ ;
  2. 无参数、无返回值;
  3. 一个类有且只有一个析构函数。若未显示定义,系统会自动生成默认的析构函数;
  4. 对象生命周期结束时,C++编译系统自动调用析构函数;

对于编译器自动生成的默认析构函数,类似于构造函数,会对自定义类型成员调用它的析构函数;

三、拷贝构造函数

拷贝构造函数:只有单个形参,该形参时对被类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

注意:拷贝构造函数只是构造函数的一种重载形式!拷贝构造函数的参数有且只有一个!!必须使用引用传参!!,使用传值的方式会引发无穷递归引用。

class Date {
public:
	//构造函数,初始化列表
	Date(int year, int mouth, int day)
		:_year(year)
		, _mouth(mouth)
		, _day(day)
	{
		cout << "Date()" << endl;
	}
	//拷贝构造函数
	Date(const Date& d) {
		_year = d._year;
		_mouth = d._mouth;
		_day = d._day;
	}
	//析构函数
	~Date() {
		cout << "~Date()" << endl;
	}
private:
	int _year;
	int _mouth;
	int _day;
};

同样的,如果没有显示定义,系统将会生成默认的拷贝构造函数,但是默认的构造拷贝函数时按照内存存储的字节序完成拷贝,这种拷贝我们称为浅拷贝(值拷贝)。

四、赋值操作符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通函数类似;

函数名字:关键字operator+需要重载的运算符符号;

函数原型:返回值类型operator操作符(参数列表);

注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型或者枚举类型的操作数
  3. 用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义 作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的 操作符有一个默认的形参this,限定为第一个形参
  4. .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载!!!
class Date {
public:
	/*
	Date(int year,int mouth,int day){
		_year = year;
		_mouth = mouth;
		_day = day;
	}
	*/
	//构造函数,初始化列表
	Date(int year, int mouth, int day)
		:_year(year)
		, _mouth(mouth)
		, _day(day)
	{
		cout << "Date()" << endl;
	}
	//拷贝构造函数
	Date(const Date& d) {
		_year = d._year;
		_mouth = d._mouth;
		_day = d._day;
	}
	//赋值运算符重载
	bool operator=(const Date& d) {
		if (this != &d) {
			_year = d._year;
			_mouth = d._mouth;
			_day = d._day;
		}
	}
	//运算符重载
	bool operator==(const Date& d) {
        return _year == d._year
            && _mouth == d._mouth
            && _day == d._day;
	}
	//析构函数
	~Date() {
		cout << "~Date()" << endl;
	}
private:
	int _year;
	int _mouth;
	int _day;
};

五、const成员

const修饰的类成员函数称之为 const 成员函数,const修饰类成员函数,实际修饰该成员函数隐含的 this 指针,表明在该成员函数中不能对类的任何成员进行修改;

class Date{
public :
    void Display (){
        cout<<"Display ()" <<endl;
        cout<<"year:" <<_year<< endl;
        cout<<"month:" <<_month<< endl;
        cout<<"day:" <<_day<< endl<<endl ;
    }
    void Display () const{
        cout<<"Display () const" <<endl;
        cout<<"year:" <<_year<< endl;
        cout<<"month:" <<_month<< endl;
        cout<<"day:" <<_day<< endl<<endl;
    }
private :
    int _year ; // 年
    int _month ; // 月
    int _day ; // 日
};
void Test (){
    Date d1 ;
    d1.Display ();
    const Date d2;
    d2.Display ();
}

六、取地址及const取地址操作符重载

这两个函数一般不用重新定义,编译器会默认生成;

class Date{
public :
    Date* operator&(){
        return this ;
    }
    const Date* operator&()const{
        return this ;
    }
private :
    int _year ; // 年
    int _month ; // 月
    int _day ; // 日
}  
发布了79 篇原创文章 · 获赞 28 · 访问量 7776

猜你喜欢

转载自blog.csdn.net/weixin_43753894/article/details/99238591