目录
前言
默认成员函数
构造函数
1.介绍
2.注意点
析构函数
1.介绍
2.注意点
拷贝构造函数
1.介绍
2.注意点
赋值运算符重载
1.介绍
2.注意点
取地址及const取地址操作符重载
1.介绍
2.注意点
后记
前言
在学习c++的过程中,我们知道,c++是面向对象的语言,有这样三个特性——封装、继承、多态,在类和对象阶段研究封装的特性,而类的默认成员函数正是实现封装特性的大框架,在认识默认成员函数之后,对于类的封装特性会有进一步的理解,这也属于c++后续知识的根基中的根基,务必对此要反复学习,下面就来详细介绍一下类的默认成员函数。
默认成员函数
默认成员函数是用户没有显示实现,编译器自动生成的成员函数,在一个空类中,编译器会自动生成6个默认构造函数,分别为默认构造函数、默认析构函数、默认拷贝构造函数、赋值运算符重载、取地址及const取地址操作符重载,在这六个之中,前四个较为重要,最后两个较为不重要,因为很少需要用户实现,使用默认生成的即可。
有同学会说,既然编译器可以自动生成,那我们为什么还要学习它们,直接使用编译器生成的不就行了?不可以,因为自动生成的默认成员函数无法满足所有类的实现,无法完美得当的实现一个类的初始化、销毁等操作,大部分的类还是会需要用户自己来实现,下面会针对每一个默认成员函数进行具体的讲解。
-
构造函数
1.介绍
构造函数是一个特殊的成员函数,作用并不是开辟空间,而是初始化对象,在对象整个生命周期内只调用一次。
特征:
①.构造函数名与类名相同;
②.函数无返回值;
③.无需用户调用,而是编译器自动调用;
④.可重载。
2.注意点
①.如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,当用户显式定义,编译器将不再生成;
②.默认构造函数包括 用户显示定义的无参的构造函数和全缺省的构造函数 以及 编译器自动生成的构造函数,并且默认构造函数只能有一个;
③.当用户显示定义了一个构造函数,既不是无参也不是全缺省,同时编译器也不会自动生成,那么就会报错,提示无默认构造函数可用;
④.(重要)大部分类都需要用户自己写构造函数,只有内置类型不需要初始化或者无内置类型,只有自定义类型的类不需要显示写,因为自定义类型会去调用自己的构造函数。(内置类型包括int、char......,自定义类型包括struct、class等自定义出来的类型)
eg:
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.介绍
析构函数是一个特殊的成员函数,作用并不是销毁对象,而是销毁对象中的资源,在对象整个生命周期内只调用一次。
特征:
①.析构函数名是在类名前加上字符 ~;
②.函数无返回值;
③.无需用户调用,而是编译器自动调用,一个类只能有一个析构函数;
④.不可重载。
2.注意点
①.与构造函数类似,不处理内置类型,自定义类型会去调用自己的析构函数,因为内置类型会在函数结束后被系统将内存回收掉;
②.(重要)若类中没有申请资源,析构函数可以不写,直接使用编译器生成的默认析构函数,当有资源申请时,一定要写,否则会造成资源泄漏。
eg:
class Stack
{
public:
Stack(int capacity = 0)
{
//...
}
~Stack()
{
delete[] _arr;
_arr = nullptr;
_top = _capacity = 0;
}
private:
T* _arr;
size_t _top;
size_t _capacity;
};
-
拷贝构造函数
1.介绍
拷贝构造函数是一个特殊的成员函数,作用是使用已有对象创建新对象。
特征:
①.是构造函数的一个重载形式;
②.只有一个形参,就是已存在对象的引用,常用const修饰,即拷贝此对象。
2.注意点
①.参数必须是引用,若是传值调用,会报错,因为传值调用本身就会调用拷贝构造函数,导致无穷调用;
②.若未显式定义,编译器会生成默认的拷贝构造函数,但是浅拷贝,需要深拷贝的地方一定要自己显示定义拷贝构造函数;
③.在编译器生成的默认拷贝构造函数中,内置类型是浅拷贝,而自定义类型则是调用自己的拷贝构造函数;
④.(重要)类中如果没有申请资源,拷贝构造函数是否写都可以;当涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
eg:
class Date
{
public:
Date(int year, int minute, int day)
{
//...
}
Date(const Date& d) //拷贝构造函数
{
//...
}
private:
int _year;
int _month;
int _day;
};
-
赋值运算符重载
1.介绍
赋值运算符重载,实现赋值运算符(=)可适用于自定义类型,语法格式:T& operator=(const T& t){} 。
特征:
①.const T&,传递引用可以提高传参效率;
②.T&,返回引用是为了支持连续赋值;
③.返回*this ,要符合连续赋值的含义。
2.注意点
①.赋值运算符只能重载成类的成员函数,不能重载成全局函数,因为赋值运算符如果不显式实现,编译器会生成默认,此时用户在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载发生冲突;
②.用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以浅拷贝形式进行拷贝;
③.无需用户调用,而是编译器自动调用,一个类只能有一个析构函数;
④.如果类中未涉及到资源管理,赋值运算符是否实现都可以,当涉及到资源管理则必 须要显示实现。
eg:
class Time
{
public:
Time()
{
//...
}
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;
};
-
取地址及const取地址操作符重载
1.介绍
取地址操作符重载,与赋值运算符重载类似,实现取地址操作符(&)可适用于自定义类型。
2.注意点
一般不需要用户自己定义,直接使用编译器生成的默认取地址重载即可,特殊情况才需要自己写。
eg:
class Date
{
public :
Date* operator&() //取地址操作符重载
{
return this ;
}
const Date* operator&() const //const取地址操作符重载
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
后记
在学习类的默认成员函数时,会存在很多细节没能够琢磨明白,或者说很难理解明白,一定要反复吸收,反复理解,才能够摸清一点门道,作为c++的根基中的根基,希望大家能够重视对类和对象的学习,如果有什么问题,欢迎在评论区讨论或者私我哦,拜拜。