构造函数和析构函数
构造函数的定义
构造函数主要用于在创建对象的时候对对象和成员属性进行赋值,构造函数由编译器自动调用,无需手动调用。
构造函数的性质
①构造函数没有返回值,也不写void。
②构造函数的函数名要和类名一致。
③构造函数时可以有参数,可以发生重载。
④程序在运行时会自动调用构造函数,无需手动调用,并且只调用一次。
#include <iostream>
using namespace std;
class test
{
public:
test()
{
cout<<"调用构造函数"<<endl;
}
};
int main()
{
test test;
}
构造函数重载分类和调用
1.按参数分为:有参构造和无参构造
无参构造就和上面的时一样的。
有参构造:
#include <iostream>
using namespace std;
class test
{
public:
test(int num )
{
cout<<"调用构造函数test(int num )"<<endl;
}
};
int main()
{
test test(10);
}
2.按类型分为:普通构造和拷贝构造
上面的有参构造和无参构造都属于普通构造
拷贝构造:
拷贝构造函数(或复制构造函数)是另外一种特殊的构造函数,具有一般构造函数的所有特性,主要用于通过一个已存在的类对象创建一个新的类对象时实现对象之间数据成员的复制操作。
#include <iostream>
using namespace std;
class test
{
public:
test()
{
cout<<"调用构造函数test( )"<<endl;
}
test(int num )
{
cout<<"调用构造函数test(int num )"<<endl;
}
test(const test & test)
{
cout<<"调用构造函数test(const test & test )"<<endl;
}
};
int main()
{
test test1(10); // 有参构造/普通构造
test test2(test1); // 拷贝构造
}
3.拷贝构造函数调用时机
①使用一个已经创建完毕的对象来初始化一个新对象;
②值传递的方式给函数参数传值;
#include <iostream>
using namespace std;
class test
{
public:
test()
{
cout<<"调用构造函数test( )"<<endl;
}
test(int num )
{
cout<<"调用构造函数test(int num )"<<endl;
}
test(const test & test)
{
cout<<"调用构造函数test(const test & test )"<<endl;
}
};
void testfunction(test & test)
{
cout<<"函数1"<<endl;
}
void testfunction1(test test)
{
cout<<"函数2"<<endl;
}
int main()
{
test test1(10); // 有参构造/普通构造
test test2(test1); // 拷贝构造
testfunction(test1); //调用拷贝构造
testfunction1(test1);
}
4.拷贝构造函数的调用规则
①创建一个类,C++编译器会给每个类都添加至少3个函数:默认构造函数(空实现)、析构函数(空实现)、拷贝构造函数(成员属性进行简单复制(浅复制);)
②如果用户定义有参构造函数,C++不在提供默认无参构造,但是会提供默认拷贝构造;
③如果用户定义拷贝构造函数,C++不会再提供其他构造函数;
浅拷贝(并不是所有的赋值最后结果都是公用一个地址):
#include <iostream>
using namespace std;
class test
{
public:
int num;
test()
{
cout<<"调用构造函数test( )"<<endl;
}
test(int num )
{
this->num = num;
cout<<"调用构造函数test(int num )"<<endl;
}
/*test(const test & test)
{
cout<<"调用构造函数test(const test & test )"<<endl;
} */
};
int main()
{
test test1(10); // 有参构造/普通构造
cout <<"test1:num:"<<test1.num<<endl;
test test2(test1); // 拷贝构造
cout <<"test2:num:"<<test2.num<<endl;
cout <<"test1:num address:"<<&test1.num<<endl; //两个的地址是不一样的。
cout <<"test1:num address:"<<&test2.num<<endl;
test1.num = 20;
cout <<"test1:num:"<<test1.num<<endl; // 20
cout <<"test2:num:"<<test2.num<<endl; // 10
}
#include <iostream>
using namespace std;
class test
{
public:
int num;
int *p;
test()
{
cout<<"调用构造函数test( )"<<endl;
}
test(int num )
{
p = new int ;
*p = num;
cout<<"调用构造函数test(int num )"<<endl;
}
/*test(const test & test)
{
this->num = test.num;
cout<<"调用构造函数test(const test & test )"<<endl;
} */
};
int main()
{
test test1(10); // 有参构造/普通构造
cout <<"test1:*p:"<<test1.p<<endl; //打印出来的地址是一样的
test test2(test1); // 拷贝构造
cout <<"test2:*p:"<<test2.p<<endl;
}
析构函数
析构函数作用:主要作用在于对象销毁前系统会自动调用,执行一些清理工作;
析构函数的性质
①析构函数,没有返回值也是不写void;
②析构函数名称与类名称是相同的,在名称前加一个~线;
③析构函数是不可以有参数,因此不可以实现重载;
④程序在对象销毁时会自动调用析构函数,无需进行手动调用,有且只调用一次;
#include <iostream>
using namespace std;
class test
{
public:
int num;
int *p;
test()
{
cout<<"调用构造函数test( )"<<endl;
}
test(int num )
{
p = new int ;
*p = num;
cout<<"调用构造函数test(int num )"<<endl;
}
test(const test & test)
{
p = new int ;
cout<<"调用构造函数test(const test & test )"<<endl;
}
~test()
{
cout<<"调用析构函数"<<this->get_value()<<"test(const test & test )"<<endl;
delete(p);
}
int get_value()
{
return *p;
}
};
int main()
{
test test1(10); // 有参构造/普通构造
cout <<"test1:*p:"<<test1.p<<endl; //打印出来的地址是一样的
test test2(test1); // 拷贝构造
cout <<"test2:*p:"<<test2.p<<endl;
cout <<"value1:"<<test1.get_value()<<endl;
cout <<"value2:"<<test2.get_value()<<endl;
}
初始化列表
与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。
#include <iostream>
using namespace std;
class test
{
public:
int num;
int grade;
test(int num ,int grade):num(num),grade(grade)
{
cout<<"调用构造函数test( )"<<endl;
}
void get_value()
{
cout<<"num : "<<this ->num <<endl;
cout<<"grade : "<<this ->grade <<endl;
}
};
int main()
{
test test(10,20);
test.get_value();
}
使用初始化变量的好处
①类成员中存在常量,如const int a,只能用初始化不能复制。
②类成员中存在引用,同样只能使用初始化不能赋值。
③提高效率。
class test
{
public:
int num;
int &A;
test():num(1),A(num)
{
cout<<"调用构造函数test( )"<<endl;
}
void get_value()
{
cout<<"num : "<<this ->num <<endl;
//cout<<"grade : "<<this ->grade <<endl;
cout<<"A address : "<<A <<endl;
}
};
int main()
{
test test;
test.get_value();
test.num = 5;
test.get_value();
}