构造函数和析构函数
对象的构造和析构
构造和析构函数,这两个函数将会被编译器自动调用,构造函数完成对象的初始化动作,析构函数在对象清理工作。
注意:对象的初始化和清理工作时编译器强制我们要做的事情,即使你不提供初始化操作和清理操作,编译器也会增加默认的操作,只是这个默认初始化操作不会做任何事。
构造函数:实例化对象的时候系统自动调用
析构函数:对象释放的时候系统自动调用
构造和析构函数的定义
构造函数语法:构造函数函数名和类名相同,没有返回类型,连void都不可以,但可以有参数。
析构函数语法:构造函数函数名是在类名前面加“~”组成,没有返回类型,连void都不可以,不能有参数,不能重载。
例:
#include <iostream>
using namespace std;
class data{
public:
int num;
public:
//构造函数
data(){
num = 0;
cout<<"无参的构造函数= "<<num<<endl;
}
data(int n){
num = n;
cout<<"有参的构造函数= "<<num<<endl;
}
//析构函数
~data(){
cout<<"析构函数"<<endl;
}
};
int test(void){
data ob1;
return 0;
};
int main(int argc, char *argv[])
{
cout << "-----001--------" << endl;
test();//类实例化对象,系统自动调用构造函数
cout << "-----002--------" << endl;
data ob;
cout << "-----003--------" << endl;
return 0;
}
类的实例化,系统自动调用构造函数,在test()中ob1是局部对象,因此在test()结束时调用析构:而ob是对象在main中,因此在main函数结束时调用析构函数。
构造函数分类
按参数:无参构造和有参构造函数
按类型:普通构造和拷贝(复制)构造函数
构造函数的调用
调用形式:
#include <iostream>
using namespace std;
class data{
public:
int num;
public:
//构造函数
data(){
num = 0;
cout<<"无参的构造函数= "<<num<<endl;
}
data(int n){
num = n;
cout<<"有参的构造函数= "<<num<<endl;
}
//析构函数
~data(){
cout<<"析构函数= "<<num<<endl;
}
};
int test(void){
data ob1; //调用无参构造或默认构造(隐式调用构造函数)
data ob2 = data(); //显示式调用构造函数
data ob3(10); //调用有参构造函数(隐式调用)=ob3.data(10)
data ob4 = data(20); //调用有参构造函数(显式调用)=ob4.data(20)
//隐式转换的方式 调用有参构造(针对只有一个数据成员)少用
data ob5 = 30; //=ob5.data(30)
//匿名对象
cout << "-----匿名对象--------" << endl;
data(40); //当前语句结束,匿名对象立即释放
cout << "-----匿名对象释放--------" << endl;
return 0;
};
int main(int argc, char *argv[])
{
cout << "-----001--------" << endl;
test();//类实例化对象,系统自动调用构造函数
cout << "-----002--------" << endl;
//data ob;
cout << "-----003--------" << endl;
return 0;
}
析构函数的调用是出栈的顺序(后入先出),在同一作用域构造和析构顺序相反
拷贝构造函数的调用
//拷贝构造函数
Date(const Data &ob){
cout<<"拷贝构造函数"<<endl;
}
顾名思义,拷贝构造函数用于对象复制对方的构造函数
如果不定义,则系统会有默认的拷贝构造函数
#include <iostream>
using namespace std;
class Data{
public:
int num;
public:
//构造函数
Data(int n){
num = n;
cout<<"构造函数= "<<num<<endl;
}
// //拷贝构造函数
// Date(const Data &ob){
// cout<<"拷贝构造函数"<<endl;
// }
//析构函数
~Data(){
cout<<"析构函数= "<<num<<endl;
}
};
int test(void){
Data ob1(10);
Data ob2 = ob1;
cout <<"ob1.num= "<<ob1.num<< endl;
cout <<"ob2.num= "<<ob2.num<< endl;
return 0;
};
int main(int argc, char *argv[])
{
cout << "-----001--------" << endl;
test();//类实例化对象,系统自动调用构造函数
cout << "-----002--------" << endl;
//data ob;
cout << "-----003--------" << endl;
return 0;
}
如图ob2默认拷贝了ob1的构造函数,因为是系统默认的, 因此未显示。
- 用户不实现拷贝构造,系统会调用默认的拷贝构造;
- 默认的拷贝构造也就是单纯的整体赋值(浅拷贝);
- 如果用户实现了,系统调用用户实现的拷贝函数;
用户定义了拷贝构造:
#include <iostream>
using namespace std;
class Data{
public:
int num;
public:
//构造函数
Data(int n){
num = n;
cout<<"构造函数= "<<num<<endl;
}
//拷贝构造函数
Data(const Data &ob){
num = ob.num*ob.num;
cout<<"拷贝构造函数"<<endl;
}
//析构函数
~Data(){
cout<<"析构函数= "<<num<<endl;
}
};
int test(void){
Data ob1(10);
Data ob2 = ob1;
cout <<"ob1.num= "<<ob1.num<< endl;
cout <<"ob2.num= "<<ob2.num<< endl;
return 0;
};
int main(int argc, char *argv[])
{
cout << "-----001--------" << endl;
test();//类实例化对象,系统自动调用构造函数
cout << "-----002--------" << endl;
//data ob;
cout << "-----003--------" << endl;
return 0;
}
拷贝构造函数的调用
#include <iostream>
using namespace std;
class Data{
public:
int num;
public:
//构造函数
Data(int n){
num = n;
cout<<"构造函数= "<<num<<endl;
}
//拷贝构造函数
Data(const Data &ob){
num = ob.num*ob.num;
cout<<"拷贝构造函数"<<endl;
}
//析构函数
~Data(){
cout<<"析构函数= "<<num<<endl;
}
};
int test(void){
Data ob1(10);
Data ob2(ob1);//隐式调用拷贝构造函数
Data ob3 = Data(ob1);//显示调用拷贝构造函数
Data ob4 = ob1;//=隐式转换调用
cout <<"ob1.num= "<<ob1.num<< endl;
cout <<"ob2.num= "<<ob2.num<< endl;
cout <<"ob3.num= "<<ob3.num<< endl;
cout <<"ob4.num= "<<ob4.num<< endl;
return 0;
};
int main(int argc, char *argv[])
{
cout << "-----001--------" << endl;
test();//类实例化对象,系统自动调用构造函数
cout << "-----002--------" << endl;
//data ob;
cout << "-----003--------" << endl;
return 0;
}
拷贝构造函数(旧对象初始化新对象)
注意:
只是单纯的赋值,例如:
#include <iostream>
using namespace std;
class Data{
public:
int num;
public:
//构造函数
Data(){
num = 5;
cout<<"wucan构造函数= "<<num<<endl;
}
Data(int n){
num = n;
cout<<"youcan构造函数= "<<num<<endl;
}
//拷贝构造函数
Data(const Data &ob){
num = ob.num*ob.num;
cout<<"拷贝构造函数"<<endl;
}
//析构函数
~Data(){
cout<<"析构函数= "<<num<<endl;
}
};
int test(void){
Data ob1(10);
Data ob2;
cout <<"ob2.num= "<<ob2.num<< endl;
ob2 = ob1;
cout <<"ob1.num= "<<ob1.num<< endl;
cout <<"ob2.num= "<<ob2.num<< endl;
return 0;
};
int main(int argc, char *argv[])
{
cout << "-----001--------" << endl;
test();//类实例化对象,系统自动调用构造函数
cout << "-----002--------" << endl;
//data ob;
cout << "-----003--------" << endl;
return 0;
}
注意:
构造函数的调用规则:
系统会对任何一个类提供三个成员函数:
默认构造函数、默认析构函数、默认拷贝构造函数(浅拷贝)
1、如果用户提供了有参构造,将会屏蔽系统的默认构造函数。
2、如果用户提供了有参构造,不会屏蔽系统的默认拷贝构造函数。
3、如果用户提供了拷贝构造函数,将屏蔽系统的默认构造函数和默认拷贝构造函数。
总结
对于构造函数:用户一般要实现无参构造、有参构造、拷贝构造、析构函数。
深拷贝和浅拷贝问题
浅拷贝:拷贝对象和被拷贝对象指向同一存放区域,在释放时会导致空间被释放两次
#include <iostream>
#include <string.h>
using namespace std;
class Person{
private:
char* name;
int num;
public:
Person(){
cout<<"无参构造"<<endl;
}
Person(char* n, int nu){
//因为name指针无指向,为name申请空间
//C语言的方式,从堆处申请
name = (char*)calloc(1,strlen(n)+1);//n传过来不会包含/0,因此需要+1给/0
if(name == NULL){
cout<<"构造失败"<<endl;//因为C语言的calloc申请空间容易失败
}
cout<<"申请空间"<<endl;
strcpy(name, n);
num = nu;
cout<<"有参构造"<<endl;
}
~Person(){//析构函数作用:在结束时释放空间
if(name != NULL){
free(name);
name = NULL;
cout<<"释放空间"<<endl;
}
cout<<"析构"<<endl;
}
void show(void){
cout<<"name= "<<name<<" age= "<<num<<endl;
}
};
int main(int argc, char *argv[])
{
Person lucy("lucy", 20);
lucy.show();
//浅拷贝问题
Person bob = lucy;
return 0;
}
(申请一次释放两次)
拷贝构造函数可以通过自定义形成深拷贝,解决浅拷贝的问题
#include <iostream>
#include <string.h>
using namespace std;
class Person{
private:
char* name;
int num;
public:
Person(){
cout<<"无参构造"<<endl;
}
Person(char* n, int nu){
//因为name指针无指向,为name申请空间
//C语言的方式,从堆处申请
name = (char*)calloc(1,strlen(n)+1);//n传过来不会包含/0,因此需要+1给/0
if(name == NULL){
cout<<"构造失败"<<endl;//因为C语言的calloc申请空间容易失败
}
cout<<"申请空间"<<endl;
strcpy(name, n);
num = nu;
cout<<"有参构造"<<endl;
}
Person(const Person &o){
//因为name指针无指向,为name申请空间
//C语言的方式,从堆处申请
name = (char*)calloc(1,strlen(o.name)+1);//n传过来不会包含/0,因此需要+1给/0
if(name == NULL){
cout<<"构造失败"<<endl;//因为C语言的calloc申请空间容易失败
}
cout<<"申请空间"<<endl;
strcpy(name, o.name);
num = o.num;
cout<<"有参构造"<<endl;
}
~Person(){//析构函数作用:在结束时释放空间
if(name != NULL){
free(name);
name = NULL;
cout<<"释放空间"<<endl;
}
cout<<"析构"<<endl;
}
void show(void){
cout<<"name= "<<name<<" age= "<<num<<endl;
}
};
int main(int argc, char *argv[])
{
Person lucy("lucy", 20);
lucy.show();
//浅拷贝问题
Person bob = lucy;
return 0;
}
(申请两次,释放两次)
注:本文档仅学习总结