构造函数与析构函数
C++中构造函数在函数初始化的时候自动调用,名字跟类名一样,析构函数在对象销毁的时候自动调用,先创建的对象后销毁,栈模式,并且析构函数无任何返回值,通过析构函数,常用来释放某些资源。构造函数可以被重载,而析构函数不能被重载,因为析构函数无返回值和无参数决定了它只能拥有一个
class Test{
public:
Test(){
this->name = (char *)malloc(sizeof(char) * 100);
cout<<"我是一个无参构造函数"<<endl; //构造函数,常常用来初始化某些属性
}
Test(int a){
this->a = a;
cout<<a<<endl; //有参构造函数,常常用来初始化某些属性
}
~Test(){
if(this->name){
free(this->name);
}
cout<<"我是析构函数"<<endl; //析构函数,常常用来释放某些资源
}
private:
char * name;
int a;
}
值得注意的是,一个类中,会自动生成午参构造函数,不管你定义没有定义,都会自动生成,如果定义了有参构造函数,那么该类就不会再默认定义无参构造函数,所以你这里如果你想创建默认无初始化参数的对象,那么就需要自己在类中定义一个无参构造函数。
但是在C++中你可能会简单这样调用的构造函数的方法
Test t = 1;
这样写就等于调用了Test(int a)这个构造函数,当然,你可以使用逗号表达式,例如
Test t = a+1,a
Test t1 = Test(1,2);
像如上这种写法,在早期的处理器中调用完Test类的Test(1,2)构造器后,又会调用t1的构造器,所以这里调用了2次构造函数,后面的编译器做了优化,Test(1,2)只会调用一次,并调用默认的拷贝构造函数,赋值给t2
C++中copy构造函数
在上面讲到的,Test t1 = Test(1,2);的时候,会调用Test类中的拷贝构造函数,将Test(1,2)匿名对象拷贝给t1,如下写法能帮助你更容易理解拷贝构造函数的使用方法
class T{
private:
int a;
public:
T(int a){
this->a = a;
}
};
int main(){
T t1(1,2);
T t2 = t1; //将t1对象赋值给t2
return 0;
}
至于拷贝构造函数是如何实现的,我认为,它是将t1中的各个成员属性的值复制给了t2,我们甚至可以在拷贝构造函数中,实现我们自己需要的逻辑
class T{
class T{
private:
int a;
public:
T(int a){
this->a = a;
}
T(const T & t){
this.a = t.a + 100;
}
int getA(){
return this->a;
}
};
当你使用T t2 = t1的时候,这时候,会让a的值不是单纯的拷贝,而是在原来的基础+100,同样的,你还可以在这个拷贝函数中实现你需要的逻辑。这里你可能还会有另外一个疑惑,a明明是私有属性,原则上是不能被直接访问的,为什么这里还能能通过t.a来访问到呢,原因是,它们属于同一个类,编译器在找t的属性的时候,不会去通过对象作用域来访问,而是直接在当前类中访问,这一点,在java中也一样。
T t1;
T t2;
t2 = t1;
像这种情况,在t2=t1时,是不会调用任何构造函数,它只是一个赋值。
再来看如下写法
T newT(){
T t(1,2);
return t;
}
int main(){
newT();
return 0;
}
如上写法会调用一次拷贝构造函数,有人会感到奇怪,为什么会调用拷贝构造函数呢?其实是这样的,再newT()中,先通过一般构造函数生成t对象,然后通过拷贝构造函数,拷贝给一个匿名对象,然后再调用析构函数析构了t对象,这时候newT();这个函数就执行完了,最后main函数执行到最后,匿名对象也被析构
T t = newT();
如上写法也只会调用1次拷贝构造函数,2次析构函数,有人认为,这里newT()返回了一个匿名对象,然后通过拷贝构造函数,再将这个对象拷贝给新的t对象,再加上之前的那次拷贝构造函数,不是2次吗?哈哈哈,我之前也是这么理解的,但是,事实并非如此,C++设计者为了提高编译器效率,在这里做了优化,t = new T();不会再调用拷贝构造函数了,而是直接将匿名对象转换成了有名字的t对象。
再看如下写法
T t2;
t2 = newT();
如上写法是构造了3次(2次构造,一次拷贝),析构了3次
首先创建t2对象,然后newT函数中右创建一个t对象,然后将这个对象拷贝给一个匿名对象,再将newT中的t对象析构,然后将这个对象赋值给外面的t2对象,而此时的匿名对象被析构,析构完之后,当函数退出,t2对象也被析构
#include "iostream"
using namespace std;
class T {
private:
int a;
public:
T(int a ) {
this->a = a;
cout << "构造函数被调用" << endl;
}
T(const T & t) {
this->a = t.a + 1;
cout << "拷贝构造函数被调用" << endl;
}
~T() {
cout << this->a << endl;
cout << "析构函数被调用" << endl;
}
};
T newT() {
T t(1);
return t;
}
void test() {
T t(3);
t = newT();
}
int main() {
test();
system("pause");
return 0;
}
最后得出的结论是,构造了多少次,就必须析构多少次。