郑州小企业网站建设,昆明网络推广,海南网页设计公司,开饰品店网站建设预算目录
一、构造函数
1.1 构造函数的引入
1.2 构造函数的定义和语法
1.2.1 无参构造函数#xff1a;
1.2.2 带参构造函数
1.3 构造函数的特性
1.4 默认构造函数
二、析构函数
2.1 析构函数的概念
2.2 特性 如果一个类中什么成员都没有#xff0c;简称为空类。 空类中…
目录
一、构造函数
1.1 构造函数的引入
1.2 构造函数的定义和语法
1.2.1 无参构造函数
1.2.2 带参构造函数
1.3 构造函数的特性
1.4 默认构造函数
二、析构函数
2.1 析构函数的概念
2.2 特性 如果一个类中什么成员都没有简称为空类。 空类中真的什么都没有吗并不是任何类在什么都不写时编译器会自动生成以下6个默认成员函数。 默认成员函数用户没有显式实现编译器会生成的成员函数称为默认成员函数。
class Date
{}; 一、构造函数
1.1 构造函数的引入 对于Date类有如下程序
#includeiostream
using namespace std;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(2025, 3, 5)return 0;
} 对于Date类可以通过Init公有方法给对象设置日期。但有时也会出现忘记Init初始化函数而直接Push。为避免忘记也为了方便程序撰写所以C规定了构造函数。
1.2 构造函数的定义和语法 构造函数是一种特殊的成员函数。虽然叫构造但是其任务不是开空间而是初始化对象。其特征如下 构造函数名与类名相同无返回值不需要写voidvoid是空返回值对象实例化时编译器自动调用对应的构造函数构造函数可以重载。 所以Date类构造函数可写为
1.2.1 无参构造函数
#includeiostream
using namespace std;class Date
{
public: Date(){_year 1;_month 1;_day 1;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Print();//Date d2();//err//Date d1(2024, 1, 27);//err没有与参数列表匹配的构造函数实例return 0;
}
运行结果为 此外C规定无参构造函数变量名后不能加小括号。Date d2();有可能是函数的声明返回类型是Date因为这个地方要写函数声明的话小括号中是要加参数类型的。
1.2.2 带参构造函数
#includeiostream
using namespace std;class Date
{
public:Date(){_year 1;_month 1;_day 1;}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(2025, 3, 5);return 0;
} 构造函数可以函数重载也可以改写为全缺省。
#includeiostream
using namespace std;class Date
{
public:Date(){_year 1;_month 1;_day 1;}Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}void Print{cout _year - _month - _day endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;Date d2(2025, 3, 5);return 0;
} 语法上上述两个函数也可以同时存在因为函数重载函数名虽然相同但参数不同。但是在调用Date d1;时会产生歧义编译器不知道要调用谁是要调用无参的还是要调用全缺省的。所以一般情况下我们不这样写。
1.3 构造函数的特性 1.C规定对象定义实例化的时候必须调用构造函数。 2.构造函数是默认成员函数默认成员函数的特征是我们没有显示定义编译器会自动生成一个无参的如果写了编译器就不会生成。 但是当我们这样写如下代码以后编译器调用了默认生成的构造函数但是什么也没干没有初始化。
#includeiostream
using namespace std;class Date
{
public:void func(){cout _year - _month - _day endl;}private:int _year 1;int _month 1;int _day;
};int main()
{Date d1;d1.Print();//A _aa;return 0;
}
运行过程为 运行结果为 说明了使用编译器实现的默认构造函数出来初始化的数据是随机值不是0。 C98规定默认生成的构造函数对于内置类型不做处理对于自定义类型会直接调用他的默认构造函数。即编译器对生成默认了构造函数对int不做处理但对于自定义成员类型A aa要调用A的构造函数。 内置类型/基本类型 - int/char/double/指针 自定义类型 - struct/class C11对这个语法进行补丁在声明的位置给缺省值。即不给缺省值编译器什么都不管给缺省值就默认生成了构造函数用缺省值去完成初始化。在类中默认了Date(){int _year 1;int _month 1;};
1.4 默认构造函数
#includeiostream
using namespace std;class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}Print(){cout _year - _month - _day endl;}
private:int _year 1;int _month 1;int _day;
};int main()
{Date d1;return 0;
} 当我们运行时发现上述代码报错此处编译报错提示没有默认构造函数可以用。 很多人经常理解默认构造函数就是编译器生成的那一个。编译器默认生成的构造函数是默认构造函数但只是其中之一。 无参的构造函数和全缺省构造函数也被称为默认构造函数且默认构造函数有且只能有一个。 一般情况下建议优选全缺省构造函数。 总结不需要传参就可以调用的构造函数都可以叫默认构造函数。 所以上述代码中没有无参也没有全缺省的默认构造函数此时就需要编译器就要生成一个默认构造函数。 但是编译器默认生成的构造函数是有条件的基于默认成员函数的特性即没有写显示定义的构造函数编译器才会自动生成一个无参的默认构造函数一旦用户显示定义编译器就不会再生成。 为了使上述程序能够通过需要函数重载显式定义一个默认构造函数。
#includeiostream
using namespace std;class Date
{
public:Date(){_year 1;_month 1;_day 1;}Date(int year, int month, int day){_year year;_month month;_day day;}Print(){cout _year - _month - _day endl;}
private:int _year 1;int _month 1;int _day;
};int main()
{Date d1;return 0;
}
二、析构函数
2.1 析构函数的概念 内存泄漏是不会报错的所以经常会忘记destory所以C就有了析构函数。 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。相当于destory把动态开辟的数组空间free掉不清理的话会出现内存泄漏。所以构造函数完成的不是创建析构函数完成的也不是销毁。 在函数名前加~在C语言中~表示按位取反所以选用这个符号就表示和构造函数的功能是相反的。
2.2 特性 析构函数是特殊的成员函数其特性如下 析构函数名是类名前加字符“~”没有参数也没有返回值一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数。注意析构函数不能重载对象生命周期结束时C编译系统系统自动调用析构函数。 第4点类似于构造函数构造函数在实例化的时候会自动调用。
#includeiostream
using namespace std;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;
} 程序运行结束后输出~Time()。 在main方法中根本没有直接创建Time类的对象为什么最后会调用Time类的析构函数 因为main方法中创建了Date对象d而d中包含4个成员变量其中_year_month_day三个是内置类型成员销毁时不需要资源清理最后系统直接将其内存回收即可而_t是Time类对象所以在d销毁时要将其内部包含的Time类的_t对象销毁所以要调用Time类的析构函数。 但是main函数中不能直接调用Time类的析构函数实际要释放的是Date类对象所以编译器会调用Date类的析构函数而Date没有显式提供则编译器会给Date类生成一个默认的析构函数目的是在其内部调用Time类的析构函数即当Date对象销毁时要保证其内部每个自定义对象都可以正确销毁main函数中并没有直接调用Time类析构函数而是显式调用编译器为Date类生成的默认析构函数。 注意创建哪个类的对象则调用该类的析构函数销毁那个类的对象则调用该类的析构函数。 如果类中没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数比如 Date类有资源申请时一定要写否则会造成资源泄漏比如Stack类。
#includeiostream
using namespace std;class Stack
{
public: Stack(int capacity 3){cout Stack(int capacity 3) endl;_arry (int*)malloc(capacity * sizeof(4));if(_arry NULL){perror(malloc);}_capacity capacity;}void Push(int x){_arry[_size] x;_size;}~Stack(){cout ~Stack() endl;free(_arry);_arry NULL;_size 0;_capacity 0;}private:int* _arry;int _capacity 0;int _size 0;
};//注意必须要有分号class MyQueue
{
private:Stack st1;Stack st2;int _size 0;
};//注意必须要有分号int main()
{MyQueue q;return 0;
}
运行结果为 2.3 析构顺序 销毁顺序为局部对象后定义的先析构-局部的静态-全局对象后定义的先析构。程序证明如下
class Date
{
public:Date(int year 1){_year year;}~Date(){cout ~Date()- _year endl;}
private:int _year ;int _month;int _day;
};void func()
{Date d3(3);static Date d4(4);
}Date d5(5);
static Date d6(6);int main()
{Date d1(1);Date d2(2);func();return 0;
} static Date d3(3);为局部静态和上边两个的存储区域不同第3是存在静态区的虽然定义在了局部但是生命周期是全局的。在main函数结束以后才会销毁。所以在这之前要先把main函数中的局部变量先销毁。