目录
1.引言
2.构造函数
1.概念
2.特性
3.析构函数
1.概念
2.特性
1.引言
如果一个类中什么都没有,叫作空类.
class A {};
那么我们这个类中真的是什么都没有吗?其实不是,如果我们类当中上面都不写.编译器会生成6个默认的成员函数。
默认成员函数:用户没有显示写 , 编译器自动生成的函数。
这里我们只介绍两个构造函数,析构函数
2.构造函数
class Stack {
public:void init(int defaultCapacity) {_a = new int[defaultCapacity];_top = 0;}void destory() {delete[] _a;_top = 0;}
private:int* _a;int _top;
};
int main() {Stack s;s.init();return 0;
}
我们想要去写一个栈,但是我们每次都要调用init去初始化非常麻烦,那么我们有没有上面方法不用写init()呢?有的,所以我们就引出了构造函数.
1.概念
构造函数是一个默认的成员函数,名字与类名相同,每次创建对象的时候自动调用,完成对象的初始化,在生命周期内只会调用一次。
2.特性
1.名字与类名相同.
2.无返回值
例如:我们上面的栈
Stack() {_a = new int[4];_top = 0;}
3.可以进行重载
带参数
Stack(int defaultCapacity) {_a = new int[defaultCapacity];_top = 0;
}不带参数
Stack() {_a = new int[4];_top = 0;
}
4.自动调用
class A {
public:A() {cout << "A()" << endl;}
};
int main() {A a;return 0;
}
例如我们有一个类A,它有一个无参的构造函数,我们在创建对象的时候,没有显示的调用构造函数,但是是我们调用的时候会打印出A().
这是因为我们的构造函数,在创建对象的时候会自动调用,来初始化对象。
5.用户定义的时候就不会再生成
我们把A改为不带构造函数的类
class A {
public:
};
int main() {A a;return 0;
}
我们看到没有报错,因为编译器在我们没有写构造函数的时候生成一个隐式不带参数的构造函数.
还是上面的例子,我们把A的构造函数改成带有一个参数的构造函数.
class A {
public:A(int a) {cout << "A(a)" << endl;}
};
int main() {A a;return 0;
}
这个时候,我们在像刚才一样创建对象编译器就会报错。
这是因为我们没有写构造函数的时候,编译器会默认生成一个不带参数的构造函数.如果我们显示写了构造函数编译器就不会生成。
6.生成默认构造对内置类型不进行处理
还是上面的例子,我们把类A中添加结果成员变量
class A {
public:int _a;double _d;int* _ptr;
};
int main() {A a;return 0;
}
这个时候我们没有显示的写构造函数,这个时候编译器会自动生成一个不带参数的构造函数.
这个时候我们想看到默认构造对内置类型做不做处理怎么办?这个时候我们可以通过调式去看
我们看一下调式结果,_a和_d都为随机值,这说明我们生成的默认构造对内置类型不做处理.那么我们以后是不是都要写构造函数呢?
其实不是,在c++在声明的时候可以给缺省值.这个时候我们给缺省值,再调式看一下结果.
7. 默认构造函数: 编译器自动生成,无参,全缺省都可以称为默认构造函数
class A {
public:A() {cout << "A()" << endl;}A(int a = 1, int b = 1) {cout << "A(int a = 1, int b = 1)" << endl;}int _a;int _b;
};
int main() {A a;return 0;
}
什么的代码编译器会报错这是为什么?因为,无参的和全缺省的都可以不传参数,编译器无法辨别调用哪一个.所以就会报错.
3.析构函数
还是上面的栈,如果我们想让销毁栈,每次都要调用destroy非常麻烦,而且有时候我们会忘记调用,这个就会导致内存泄漏导致程序崩溃。所以我们c++就引出一个新的默认成员函数叫作析构函数.
1.概念
与构造函数的功能相反,析构函数是用来清理对象内的资源的,不是用来销毁对象,局部的对象销毁,是编译器来完成的。
2.特性
1.在类名前面加上~
2.无返回值
例如:
-Stack() {
}
3.一个类中只能有一个析构函数,和构造函数一样如果我们不显示定义析构函数,编译器就会自动生成(析构函数不能重载)
4.析构函数会自动调用
class A {
public:~A() {cout << "~A()" << endl;}
};
int main() {A a;return 0;
}
我们这个代码没有显示的调用析构函数,但是最后的结果却输出~A().
这就说明了我们的析构函数和构造函数一样是自动调用.
5.编译器生成的默认成员函数对自定义类型自动调用自定义类型的构造函数
class B {
public:~B() {cout << "~B()" << endl;}
};
class A {
public:B _b;
};
int main() {A a;return 0;
}
什么代码中A类当中有一个自定义类型B,并且A当中没用显示的写析构函数,是由编译器自动生成的构造函数.我们看一下运行之后的结果是什么?
我们可以看到输出了~B(),说明编译器默认生成的析构函数,对自定义类型会去调用的它的析构函数.
6.如果类当中没有定义资源,那么我们的析构函数可以不写,直接用编译器生成的析构函数即可.