构造函数
1.构造函数样式
(1)函数名和类名相同
(2)没有返回值
(3)若无构造函数,任何类中都存在一个默认的构造函数
①默认的构造函数都是无参的
②若有构造函数,默认构造函数不存在
(4)delete可以用来删除默认函数
(5)使用默认构造函数,用default说明
(6)构造函数在构造对象的时候调用(初始化参数列表)
构造函数名(参数1,参数2,参数3,...):成员1(参数1),成员2(参数2),成员3(参数3),...{}
(7)允许构造函数调用另一个构造函数
2.构造函数用处
(1)用来构造对象
(2)多用来初始化成员
(3)构造函数重载为构造不同的对象
#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
//MM() = delete;//删除默认构造函数
MM(string nname, int nage)
{
name = nname;
age = nage;
}
//MM(){}//构造无参的构造函数
MM() = default; //默认构造函数
void print()
{
cout << name << "\t" << age << endl;
}
protected:
string name = "默认值";
int age = 0;
};
class Boy
{
public:
Boy(string nname=" ", int nage=0)//构造函数缺省
{
name = nname;
age = nage;
}
void print()
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
class Std
{
public:
Std(string name = "", int age = 0) :name(name), age(age)//初始化参数列表
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
class Girl
{
public:
Girl(string name = "", int age = 0) :name(name), age(age){}
//Girl() :Girl("默认", 1){}//构造函数可以调用另一个构造函数初始化数据(委托构造)
void print()
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
int main()
{
MM mm; //构造无参的对象,需要无参构造函数
MM mm1{ "姓名", 1 };
mm1.print();
Boy boy1;
Boy boy2("姓名");
Boy boy3("姓名", 2);
Girl girl;
girl.print();
return 0;
}
析构函数
1.析构函数样式
(1)无返回值
(2)无参数
(3)函数名:~类名
(4)存在默认析构函数
(5)无需调用,对象死亡自行调用
2.析构函数用处
(1)当类中的数据成员是指针,并且动态申请内存(手动析构)
(2)用来释放数据成员申请的内存
(3)new一个对象时,只有delete后才会调用析构函数
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Boy
{
public:
Boy(const char* pstr, int age) :age(age)
{
str = new char[strlen(pstr) + 1];
strcpy(str, pstr);
}
void print()
{
cout << str << "\t" << age << endl;
}
~Boy();
protected:
char* str;
int age;
};
Boy::~Boy()
{
cout << "析构函数" << endl;
delete[] str;
str = nullptr;
}
int main()
{
{
Boy boy("aa", 1);
}
cout << "------" << endl;
{//先释放,再调用析构函数
Boy* boy = new Boy("姓名", 1);
boy->print();
delete boy;
boy = nullptr;
}
cout << "------" << endl;
return 0;
}
拷贝构造函数
1.拷贝构造函数与构造函数长相相同,但参数固定(唯一参数:对对象的引用)
2.不写拷贝构造函数也存在默认的拷贝构造函数
3.拷贝构造函数作用:通过一个对象去初始化另一个对象
4.当存在匿名对象赋值操作的时候,必须要const修饰(vs2019)
#include <iostream>
#include <string>
using namespace std;
class Boy
{
public:
Boy() = default;
Boy(string name, int age) :name(name), age(age){}
Boy(const Boy& boycpy)//拷贝构造
{
name = boycpy.name;
age = boycpy.age;
cout << "调用拷贝构造" << endl;
}
void print()
{
cout << name << "\t" << age << endl;
}
protected:
string name;
int age;
};
void Print(Boy boy)
{
boy.print();
}
void Print1(Boy& boy)
{
boy.print();
}
int main()
{
Boy boy("姓名", 1);
boy.print();
//显示调用
Boy boy1(boy); //通过一个对象创建另一个对象
boy1.print();
//隐式调用
Boy boy2 = boy;//拷贝构造
boy2.print();
cout << "---" << endl;
Boy boy3;
boy3 = boy1;//运算符重载
boy3.print();
cout << "---" << endl;
//函数传参
Print(boy);//有拷贝版生成
Print1(boy);
cout << "---" << endl;
Boy temp = Boy("匿名", 1);
return 0;
}
深层拷贝
1.浅拷贝:默认拷贝为浅拷贝,浅拷贝容易引发析构问题
2.深拷贝:拷贝构造函数中做了new内存的操作,并作拷贝赋值
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Boy
{
public:
Boy(const char* nname, int age): age(age)
{
name = new char[strlen(nname) + 1];
strcpy(name, nname);
}
void print()
{
cout << name << "\t" << age << endl;
}
~Boy()
{
delete[] name;
name = nullptr;
}
Boy(const Boy& boycpy)//深拷贝
{
name = new char[strlen(boycpy.name) + 1];
strcpy(name, boycpy.name);
age = boycpy.age;
}
protected:
char* name;
int age;
};
int main()
{
{
Boy boy("姓名", 1);
Boy boy1(boy);
Boy boy2 = boy;
boy2.print();
}
return 0;
}
构造和析构顺序问题
1.先构造的后析构
2.new出来的对象,delete后会直接调用析构
3.static对象,当程序关闭时,生命周期才结束
#include <iostream>
#include <string>
using namespace std;
class Boy
{
public:
Boy(string name="A") :name(name)
{
cout << name;
}
~Boy()
{
cout << name;
}
protected:
string name;
};
int main()
{
{
Boy boy("B");
static Boy boy1("C");
Boy* pboy = new Boy[2];
Boy boy2[2];
delete[] pboy;
pboy = nullptr;
}
return 0;
//输出BCAAAAAAAABC
}