文章目录
- 前言
- 一、基本概念
- 1 构造函数
- 2 析构函数
- 二、示例
- 1. 构造函数和析构函数的简单使用
- 2. 拷贝构造函数的调用
- 3. 浅拷贝和深拷贝
前言
本文讲述了构造函数和析构函数的概念以及对应的示例,以便加深理解。
一、基本概念
1 构造函数
构造函数用于初始化类的对象,可以由程序员自己定义,也可以由编译器定义(构造函数内为空)。
其特点:
1.没有返回类型。
2.函数名和类名相同。
3.可以有参数,也可以没有。
4.可以重载。
5.程序会自动调用。
按照参数分类:
1.无参构造函数
2.有参构造函数(包括拷贝构造函数)
3种构造方法:
1.括号法
2.显示法
3.隐式转换法
调用规则:
1.编译器会给类添加至少三个构造函数:1,默认构造函数;2,析构函数(空);3,拷贝构造函数(值拷贝):如果不写拷贝构造,编译器会自动生成一个拷贝构造函数,Name = c.Name;。
2.如果自己写了有参构造函数,编译器不会再提供默认构造函数,但还是会提供拷贝构造函数。
3.如果自己写了拷贝构造函数,编译器其他两种构造函数都不会再提供。
2 析构函数
析构函数用于销毁之前声明的类对象,系统自动调用,用~+类名声明。
1.析构函数不可以有参数。
2.析构函数无法重载。
二、示例
1. 构造函数和析构函数的简单使用
class Cat
{
public:Cat(){cout << "喵是无参构造函数" << endl;}Cat(string name){Name = name;cout << "喵是有参构造函数" << endl;}//用于拷贝c的属性值,用常量引用的方式进行Cat(const Cat &c){Name = c.Name;cout<< "喵是拷贝构造函数" << endl;}~Cat(){cout << "喵是析构函数" << endl;}string Name;//咪咪名字
};void FindName()
{//括号法Cat cat1;//用默认构造函数时,不能加括号,否则编译器会当作函数声明。Cat cat2(cat1);//拷贝构造函数调用Cat cat3("小300");//有参构造函数调用。Cat cat4(cat3);//拷贝构造函数调用cout << "第一个猫的名字是:" << cat1.Name << endl;cout << "第二个猫的名字是:" << cat2.Name << endl;cout << "第三个猫的名字是:" << cat3.Name << endl;cout << "第四个猫的名字是:" << cat4.Name << endl;//显示法Cat cat5;//默认构造函数Cat cat6 = Cat("三号楼");//有参构造函数调用。Cat cat7 = Cat(cat6);//拷贝构造函数调用Cat("蹭铁棍");//匿名对象,会直接调用构造函数和析构函数,再去执行后面的内容。//Cat(cat7);不要匿名初始化拷贝构造函数cout << "第五个猫的名字是:" << cat5.Name << endl;cout << "第六个猫的名字是:" << cat6.Name << endl;cout << "第七个猫的名字是:" << cat7.Name << endl;//隐式调用string name8 = "来两根";Cat cat8 = name8;cout << "第八个猫的名字是:" << cat8.Name << endl;
}int main()
{FindName();
}
喵是拷贝构造函数
喵是普通有参构造函数
喵是拷贝构造函数
第一个猫的名字是:
第二个猫的名字是:
第三个猫的名字是:小300
第四个猫的名字是:小300
喵是无参构造函数
喵是普通有参构造函数
喵是拷贝构造函数
喵是普通有参构造函数
喵是析构函数
第五个猫的名字是:
第六个猫的名字是:三号楼
第七个猫的名字是:三号楼
喵是普通有参构造函数
第八个猫的名字是:来两根
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
2. 拷贝构造函数的调用
void eat1(Cat cat)
{cout << cat.Name << "吃猫粮" << endl;
}Cat eat2()
{Cat cat("炸糊的栗子");cout << cat.Name << "吃骨头" << endl;return cat;
}
void FindName()
{//使用一个已经创建的对象来初始化新的对象Cat cat1("小300");//有参构造函数调用。Cat cat2(cat1);//拷贝构造函数调用cout << "第一个猫的名字是:" << cat1.Name << endl;cout << "第二个猫的名字是:" << cat2.Name << endl;//值传递传值 Cat cat3("烤糊的栗子");eat1(cat3);cout << "第三个猫的名字是:" << cat3.Name << endl;//值方式返回局部对象Cat cat4 = eat2();cout << "第四个猫的名字是:" << cat4.Name << endl;
}
喵是普通有参构造函数
喵是拷贝构造函数
第一个猫的名字是:小300
第二个猫的名字是:小300
喵是普通有参构造函数
喵是拷贝构造函数
烤糊的栗子吃猫粮
喵是析构函数
第三个猫的名字是:烤糊的栗子
喵是普通有参构造函数
炸糊的栗子吃骨头
喵是拷贝构造函数
喵是析构函数
第四个猫的名字是:炸糊的栗子
喵是析构函数
喵是析构函数
喵是析构函数
喵是析构函数
3. 浅拷贝和深拷贝
深拷贝:在堆区开辟空间,完成拷贝。
浅拷贝:简单赋值拷贝的方式就属于浅拷贝,比如默认的拷贝构造函数。
class Cat
{
public:Cat(){cout << "喵是无参构造函数" << endl;}//Cat(string name)//{// Name = name;// cout << "喵是普通有参构造函数" << endl;//}Cat(string name, int age){Name = name;Age = new int(age);cout << "喵是普通有参构造函数" << endl;}Cat(const Cat &c){Name = c.Name;//深拷贝,用new将传入Age的地址解引用然后在堆区重新创建一个空间,与cat3所指向的新内存空间就不一样了,不会发生析构函数重复释放报错的问题。Age = new int(*c.Age);cout<< "喵是拷贝构造函数" << endl;}~Cat(){if (Age != NULL){delete Age;Age = NULL;}cout << "喵是析构函数" << endl;}string Name;//咪咪名字int *Age;//咪咪年龄
};void FindName()
{浅拷贝,仅发生值传递//Cat cat1("小300");//Cat cat2(cat1);////cout << "第一个猫的名字是:" << cat1.Name << endl;//cout << "第二个猫的名字是:" << cat2.Name << endl;//深拷贝,用new在内存中开辟新空间Cat cat3("小300",2);Cat cat4(cat3);cout << "第三个猫的名字是:" << cat3.Name << endl;cout << "第三个猫的年龄是:" << *cat3.Age << endl;cout << "第四个猫的名字是:" << cat4.Name << endl;cout << "第四个猫的年龄是:" << *cat4.Age << endl;
}int main()
{FindName();
}
喵是普通有参构造函数
喵是拷贝构造函数
第三个猫的名字是:小300
第三个猫的年龄是:2
第四个猫的名字是:小300
第四个猫的年龄是:2
喵是析构函数
喵是析构函数