C++构造函数和析构函数
类中的特殊的函数
文章目录
- 类中的特殊的函数
- 一、构造函数
- (1)默认(无参)构造函数
- (2)有参构造函数
- 初始化列表
- (3)拷贝构造函数
- 构造函数的调用
- 构造函数的调用规则
- 浅拷贝函数和深拷贝函数
- 二、析构函数
一、构造函数
在每一个类中都会至少有一个构造函数,在每一个对象被创建的时候会自动调用,如果我们不写构造函数,编译器会自动帮我们去写,一旦我们写了一个构造函数编译器便不会在帮我们去写了,但是每一个函数的函数名相同,都和类名相同,没有返回值也不写void,构造函数:类名()
,虽然可以有多个构造函数只是发生了重载,进而实现不同的功能,构造函数可以有参数也可以没有参数,所以可以引发重载。
(1)默认(无参)构造函数
系统自动帮我们写的构造函数,就是默认构造函数不过里面函数体内容为空,我们也可以自己去写,可以对类中的成员进行初始化。
class person
{
public:
person()
{
};//系统自动帮我们写的默认构造函数就是这种
};
class person
{
public:
person()
{
age=10;
};//可以对我们的参数进行初始化,不用传值,固定的初始化
private:
int age;
};
(2)有参构造函数
class person
{
public:
person(int c)
{
age = c ;
};
private:
int age;
};
初始化列表
对类内成员进行初始化同样有两种方法
class text
{
public:
person(int age,int heigh,int length):m_age(age),m_heigh_kg(height),m_length(length)
{
}
// 等于下面这种方法 但是更推荐上面的方法
/* person(int age,int heigh,int length)
{
m_age = age;
m_heigh_ke = heigh;
length = m_length;
}*/
private:
int m_age;
int m_heigh_kg;
int m_length;
};
(3)拷贝构造函数
语法:类名(const 类名 & p);
拷贝函数的调用时机:
- 对象克隆
- 以值的方式给函数传参数
- 以值的方式返回局部对象
把一个对象的所有特征全部拷贝到自己身上,
class person
{
public:
person(const person &c)
{
age = c.age ;
};
private:
int age;
};
void text()
{
person p1;
//对象克隆
person p2(p1);
}
person text01()
{
person p1;
// 以值的方式返回局部对象
// 返回一个p1值和 int 的返回类似
return p1;
}
// 以值的方式给函数传参数
void text02(person p2)
{
}//
构造函数的调用
1.括号法
void text()
{
person p; //没写参数会默认调用无参构造函数
// person p(); //不能引发构造函数的调用,因为编译器会把这条语句当做函数的声明,返回值为person,函数名为p
person p2(10);//会调用有参构造函数
person p3(p2);//会调用拷贝构造函数
}
2.显示法
void text01()
{
person p1; //无参构造函数的调用
person p2 = person(10);// 有参构造函数的调用
person p3 = person(p2);// 拷贝构造函数的调用
// person (10) 匿名对象 当前行执行结束系统自动释放该对象
// 在创建的时候同样会调用构造函数,当前行结束的时候同样会调用析构函数
// person(p1) = person p1;
// 不要利用拷贝构造函数初始化匿名对象,编译器会认为重定义
}
3.隐式转换法
void text02()
{
person p4 = 10; //有参构造
person p5 = p4; //拷贝构造函数
}
构造函数的调用规则
(1)创建一个类,C++编译器会给每个类都添加至少3个构造函数,如果我们不写编译器会写
默认构造函数(空实现)
析构函数(空实现)
拷贝构造函数(值拷贝或者说浅拷贝)
(2)如果我们写了有参构造函数,编辑器就不会给我们提供默认构造函数,但同样会给我们提供析构函数和拷贝构造函数。
(3)如果我们写了拷贝构造函数,编辑器就不会提供其他任何构造函数了。
拷贝构造 有参构造 默认构造(无参构造) 其中如果一个有了编辑器就不会提供他后面的如果要使用所有函数只能自己写
浅拷贝函数和深拷贝函数
浅拷贝,是完全复制,就是让对应的元素相等,指针也会直接等于指针,这样会带来相应的问题,会让堆区的内存重复释放。
class person
{
public:
person()
{
height_kg = 70;
age = new int;
}
~person()
{
delete age;
age = NULL;
};
private:
int height_kg;
int *age;
}; //不要漏了分号
void text01()
{
person p1;
person p2(p1);
}
在p1,p2生命周期结束的时候会调用析构函数来释放内存因为后定义的p2,又因为是临时变量在栈上开辟数据,p2先调用其析构函数没有问题,但是当p1生命周期结束的时候再次调用析构函数对内存进行释放的时候该块内存以经被释放过了,会多次释放出现问题,所以当我们的类内元素有指针在堆区开辟内存的时候,且我们要使用拷贝构造函数,我们要自己实现拷贝构造函数(深拷贝)。
class person
{
public:
person()
{
height_kg = 70;
age = new int(20);
}
person(const person & p)
{
age=new int(*p.age);
height_kg=p.height_kg;
}
~person()
{
delete age;
age = NULL;
};
private:
int height_kg;
int *age;
}; //不要漏了分号
void text01()
{
person p1;
person p2(p1);
}
二、析构函数
在每一个类中有且仅有一个析构函数,在每一个对象被释放的时候会自动调用,如果我们不写析构函数,编译器会自动帮我们去写,析构函数没有参数不可发生重载,所以只能有一个,构造函数的函数名~函数名
。
析构函数的作用主要用来释放我们在堆区申请的内存
class person
{
~person()
{
} //系统自动帮我们写的析构函数就是这个样子的
};
class person
{
public:
person()
{
height_kg = 70;
age = new int;
}
~person()
{
delete age;
age = NULL;
};
private:
int height_kg;
int *age;
};
class person
{
public:
person()
{
height_kg = 70;
age = new int;
}
~person()
{
delete age;
age = NULL;
};
private:
int height_kg;
int *age;
};