一、初识构造函数和析构函数
简单来说,有对象生成必然会调用构造函数,有对象销毁必然会调用析构函数。构造函数的作用是初始化成员变量,是由编译器去调用的,而析构函数同理也是由编译器调用,不过他的作用则是清理。可以由下面的代码体验两个函数的使用。
注意:
相同点:两个函数都没有返回值,不能用void
不同点:构造函数可以有参数,析构函数没有参数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
M() {//无参构造
a = 101;
cout << "构造函数执行" << endl;
}
~M()//在对象销毁前,编译器调用析构函数
{
cout << "析构函数执行" << endl;
}
int a;
};
void fun() {
M m;
int b = m.a;
cout << b << endl;
}
class M2 {
public:
//有参构造
M2(const char *name,int age){
cout << "有参构造" << endl;
//从堆区空间申请
pName = (char*)malloc(strlen(name) + 1);
strcpy(pName,name);
mAge = age;
}
void Print() {
cout << "name=" << pName << endl;
cout << "age=" << mAge << endl;
}
~M2()
{
cout << "析构函数执行" << endl;
//释放堆区空间
if (pName != NULL) {
pName = NULL;
}
if (mAge != NULL) {
mAge = NULL;
}
}
private:
char* pName;
int mAge;
};
void fun2() {
M2 m2("卡卡",14);
m2.Print();
}
int main() {
fun();
M m;
cout << "***********" << endl;
fun2();
system("pause");
return EXIT_SUCCESS;
}
运行结果:
1. 构造函数可以重载
class M3 {
public:
M3() {
}
M3(int a) {
}
};
2.当构造函数私有时,无法实例化对象,所以构造函数和析构函数都是公有的
class M3 {
//public:
private:
M3() {
}
M3(int a) {
}
};
void fun3() {
M3 m3;//该行会报错
}
补充:实例化对象的时候内部操作:1.分配空间(将对象m分配到栈区)2.调用构造函数进行初始化
二、默认的构造函数和析构函数
现在我们已经简单了解了构造函数和析构函数,但当我们在声明类的时候没有声明这两个函数,那我们在实例化一个对象的时候还会有这两个函数的事情吗?
答案是有的。
前面的学习我们知道,构造函数和析构函数是由编译器去调用的,所以当我们没有声明他们的情况下,编译器会去提供默认的构造函数和析构函数。如下面的例子,程序运行可以打印a=100
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
void pfun() {
a = 100;
cout << "a=" << a << endl;
}
private:
int a;
};
void fun() {
M m;
m.pfun();
}
int main() {
fun();
system("pause");
return EXIT_SUCCESS;
}
而所提供的默认的构造函数和析构函数的函数体是空的。
三、拷贝构造
用一个已有的对象去初始化另一个对象
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
M() {
cout << "M的无参构造函数" << endl;
a = 10;
}
M(const M& t) {
cout << "拷贝构造函数" << endl;
a = t.a;
}
void printinform() {
cout << "a=" <<a<< endl;
}
private:
int a;
};
void fun() {
M m;
m.printinform();
M t(m);//用一个已有的对象去初始化另一个对象
t.printinform();
}
int main() {
fun();
system("pause");
return EXIT_SUCCESS;
}
运行结果:
相信大家这时候会注意到,在拷贝构造函数那里,我们用到了const和&。
const是为了保证其值不会改变,这里可有可没有,而&在这里表示的是引用。为了看出引用的的作用,我们可以在这里先去掉&,这个时候会发现编译器报错。
下面情况下,当对象以值的方式给函数参数时,调用的也是拷贝函数
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
M(int x) {
cout << "M的有参构造函数" << endl;
}
M() {
cout << "M的无参构造函数" << endl;
}
M(const M& t) {
cout << "拷贝构造函数" << endl;
}
~M()
{
cout << "析构函数" << endl;
}
};
void f0(M x) {//对象以值的方式给函数参数
}
void fun() {
M m;
f0(m);//对象以值的方式给函数参数
}
int main() {
fun();
system("pause");
return EXIT_SUCCESS;
}
运行:
另外,拷贝构造也可以这样调用,但不常用
M t = m;
注意区别赋值操作和拷贝构造
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
M() {
cout << "M的无参构造函数" << endl;
a = 10;
}
M(const M& t) {
cout << "拷贝构造函数" << endl;
a = t.a;
}
void printinform() {
cout << "a=" <<a<< endl;
}
private:
int a;
};
void fun() {
M m;
m.printinform();
M t(m);//用一个已有的对象去初始化另一个对象
t.printinform();
M t2;
t2 = t;//赋值操作!!!!
t2.printinform();
}
int main() {
fun();
system("pause");
return EXIT_SUCCESS;
}
可见,构造函数大概分成了以下三种。
有了拷贝构造,那么编译器提供的默认构造函数和之前有什么区别呢?
四、构造函数的调用
1.如果提供了有参构造,编译器不会提供默认构造函数,但会提供拷贝构造函数
2.如果提供了拷贝构造函数,那么编辑器不会提供默认的构造函数和默认的拷贝构造函数
五、类中有多个对象的函数调用情况
当在一个类中有多个其他类声明对象的情况下,构造函数和析构函数又是怎样调用呢?
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class A {
public:
A() {
cout << "A的无参构造函数" << endl;
}
A(const A& t) {
cout << "A的拷贝构造函数" << endl;
}
~A()
{
cout << "A的析构函数" << endl;
}
};
class B {
public:
B() {
cout << "B的无参构造函数" << endl;
}
B(const B& t) {
cout << "B的拷贝构造函数" << endl;
}
~B()
{
cout << "B的析构函数" << endl;
}
};
class M {
public:
M(int x) {
cout << "M的有参构造函数" << endl;
}
M() {
cout << "M的无参构造函数" << endl;
}
M(const M& t) {
cout << "M的拷贝构造函数" << endl;
}
~M()
{
cout << "M的析构函数" << endl;
}
private:
A m1;
B m2;
};
void fun() {
M m;
}
int main() {
fun();
system("pause");
return EXIT_SUCCESS;
}
由此可见,当对象m运行时候,先是按照顺序运行 m内声明的对象a和b,分别调用其构造函数,并按照栈的顺序调用析构函数
六、匿名对象
匿名对象就是没有给根据类声明的对象命名,如有一个类M,
M();(而不像之前声明实例对象M m)便是一个匿名对象
而匿名对象的生命周期与之前的不同,该周期是在当先行,对比下面代码的匿名对象和m对象的运行结果。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
M(int x) {
cout << "M的有参构造函数" << endl;
a = 10;
}
M() {
cout << "M的无参构造函数" << endl;
a = 10;
}
M(const M& t) {
cout << "拷贝构造函数" << endl;
a = t.a;
}
~M()
{
cout << "析构函数" << endl;
}
void printinform() {
cout << "a=" <<a<< endl;
}
private:
int a;
};
void fun() {
M();//匿名对象
cout << "1111111111111" << endl;
cout << "******************************" << endl;
M m;
cout << "2222222222" << endl;
}
int main() {
fun();
system("pause");
return EXIT_SUCCESS;
}
注意:匿名对象有名字的话,就不是匿名对象,如下面的m1
M m1 = M();
标签:函数,对象,C++,class,和析构,public,构造函数
From: https://blog.csdn.net/immnature/article/details/141093997