凡科建站收费,wordpress最好的编辑器下载地址,產品定制网站开发,wordpress 4.4 下载文章目录 一、类的六个默认成员函数二、构造函数三、析构函数 一、类的六个默认成员函数
#x1f4d6;默认成员函数 用户没有显式实现#xff0c;编译器会自动生成的成员函数#xff0c;称为默认成员函数。
构造函数#xff1a;完成对象的初始化工作。析构函数#xff… 文章目录 一、类的六个默认成员函数二、构造函数三、析构函数 一、类的六个默认成员函数
默认成员函数 用户没有显式实现编译器会自动生成的成员函数称为默认成员函数。
构造函数完成对象的初始化工作。析构函数完成对象空间的清理工作。拷贝构造使用同类对象初始化创建对象。赋值重载把一个对象赋值给另外一个对象该对象已存在。取地址重载获取对象的地址这两个很少自己实现。
注意构造和析构函数不是创建对象和销毁对象。对象的创建和销毁都是编译器做的工作。
二、构造函数
为什么要有构造函数 为了避免每次创建对象后都要去调用专门的成员函数设置对象的信息这样很麻烦并且容易遗忘那就想着能否在创建对象的同时就将信息设置进去。因此就有了构造函数。以日期类为例
class Date
{
public:void Init(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout _year - _month - _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;//第一步创建对象d1.Init(2022, 7, 5);//调用初始化函数d1.Print();Date d2;d2.Init(2022, 7, 6);d2.Print();return 0;
}如上面的代码每次创建一个日期类对象后都要手动的去调用Init函数完成对象的初始化整个过程繁琐而且容易遗忘为此提出了构造函数的概念。
定义 构造函数是一个特殊的成员函数名字与类名相同创建对象的时候由编译器自动调用以保证每个数据成员都有一个合适的初始值并且在对象的整个生命周期中只调用一次。
构造函数的特性
函数名与类名相同。无返回值。无需void对象实例化时编译器自动调用对应的构造函数。构造函数可以重载。
示例 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;};void TestDate(){Date d1; // 调用无参构造函数Date d2(2015, 1, 1); // 调用带参的构造函数Date d3();}注意如果通过无参构造函数创建对象时对象后面不用跟括号否则就成了函数声明。即Date d3();是声明了一个d3函数该函数无参返回一个日期类对象并不是创建了一个日期类对象d3。
构造函数在语法上可以是私有的但是在创建对象的时候就调不动了。在单例模式中会把构造函数搞成私有具体的我们以后再说。
编译器生成的构造函数 如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不在生成。
示例
class Date
{public:/*// 如果用户显式定义了构造函数编译器将不再生成Date(int year, int month, int day){_year year;_month month;_day day;}*/void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;return 0;
}将Date类中的构造函数注释掉后代码可以编译通过因为编译器生成了一个无参的默认构造函数。将Date类中的构造函数放开后代码编译失败因为一旦显式定义了任何构造函数编译器将不再生成默认构造函数。而此时Date中的构造函数需要三个参数Date d1;会去调用无参的构造函数但是当前类中没有无参的构造函数所以编译会报错。
编译器生成的构造函数干了什么 C中把类型分为内置类型和自定义类型。内置类型就是语言提供的数据类型如int、char……自定义类型就是我们使用class、struct、union等自己定义的类型。所有类型的指针都属于内置类型。
编译器生成的默认构造函数对内置类型不做处理对自定义类型会去调用它的默认构造函数。
示例
//先定义一个时间类
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;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}上面代码先定义了一个时间类Time它的成员变量都是内置类型给这个类写了一个无参的构造函数接下来定义了一个日期类Date他有四个成员变量其中_year、_month、 _day都是内置类型_t是自定义类型并且我们没有写日期类的构造函数这意味着在创建对象的时候会去使用编译器生成的无参默认构造函数。
内置类型给默认值 C11中针对内置类型成员不初始化的缺陷打了补丁即内置类型成员变量在类中声明时可以给默认值。
示例
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;
}默认构造函数 我们没写编译器自动生成的构造函数、无参构造函数、全缺省构造函数这三种都叫做默认构造函数它们都有一个共同的特点可以不用传参。默认构造函数只能有一个后面俩在语法上可以构成函数重载但是在无参调用的时候会发生歧义出现调用不明确。 注意要把默认构造函数和默认成员函数区分清楚默认成员函数是我们不写编译器会自动生成的默认构造函数是不需要传参的构造函数。编译器生成的构造函数既是默认构造函数同时也是默认成员函数。
总结 一般情况下都需要我们自己写构造函数。如果满足以下情况即内置类型的成员变量都有默认值且初始化符合我们的要求自定义类型都定义了默认构造此时可以考虑不写构造函数使用编译器自动生成的默认构造函数。自定义类型如果没有对应的构造函数那就意味着初始化自定义类型需要传参此时必须自己写构造函数并且还会用到初始化列表。
三、析构函数
定义 与构造函数的功能相反析构函数不是完成对对象本身的销毁局部对象的销毁工作是由编译器完成的。而对象在销毁的时候会自动调用析构函数完成对象中资源的清理工作。
特性
析构函数名是在类名前加上~。无参数无返回值类型。一个类只能有一个析构函数若未显式定义系统会自动生成默认的析构函数。对象生命周期结束时C编译器自动调用析构函数。
小Tips析构函数不能重载。
示例
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 3){_array (DataType*)malloc(sizeof(DataType) * capacity);if (NULL _array){perror(malloc申请空间失败!!!);return;}_capacity capacity;_size 0;}void Push(DataType data){// CheckCapacity();_array[_size] data;_size;}// 其他方法...~Stack()//析构函数{if (_array){free(_array);_array NULL;_capacity 0;_size 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}Stack中的成员变量_array、_capacity、_size都是内置类型所以在对象s生命周期结束要销毁的时候不需要资源清理最后系统直接将其内存回收即可而_array指向的空间是在堆区上申请的这块空间不会随着对象生命周期的结束而自动释放归还给操作系统所以_array被回收后就找不到动态申请的那块空间会造成内存泄漏因此在对象销毁前要通过析构函数去释放成员变量_array指向的空间这就是析构函数的作用。
编译器生成的析构函数干了什么 我们不写编译器会自动生成一个析构函数。该析构函数对内置类型不做处理对自定义类型会去调用它的析构函数。
示例
class Time
{
public:~Time(){cout ~Time() endl;}
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;
}main方法中创建了Date对象d而d中包含4个成员变量其中_year、_month、_day、三个是内置类型成员对象销毁时不需要资源清理最后系统直接将其内存回收即可而_t时Time类对象在d销毁时要将器内部包含的Time类的_t对象销毁所以要去调用Time类的析构函数。但是main函数中不能直接调用Time类的析构函数实际销毁的是Date类对象d所以编译器会调用Date类的析构函数而Date类没有显示提供则编译器会给Date类生成一个默认的析构函数目的是在其内部调用Time类的析构函数。
总结 一般情况下有动态申请资源就需要显式的写析构函数来释放资源没有动态申请的资源可以不写析构函数需要释放资源的成员都是自定义类型也不需要写析构函数。 结语 今天的分享到这里就结束啦如果觉得文章还不错的话可以三连支持一下您的支持就是春人前进的动力