目录
构造函数和析构函数
构造函数的分类和调用
c++默认构造的函数
浅拷贝和深拷贝
多个对象的构造和析构
初始化列表
类对象作为成员
构造函数和析构函数
对象的初始化和清理是两个非常重要的安全问题,一个对象或者变量没有初始时,对其使用后果是未知,同样的使用完一个变量,没有及时清理,也会造成一定的安全问题。c++为了给我们提供这种问题的解决方案,构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和对象清理工作。
#include <iostream>
#include <string.h>
using namespace std;
class function
{
public:
//构造函数 函数名和类名相同,没有返回值,不能有void,但可以有参数 可以重载
function(int init_age,string init_name)
{
age = init_age;
name = init_name;
cout << "构造函数调用" << endl;
}
//析构函数 函数名是在类名前面加”~”组成,没有返回值,不能有void,不能有参数,不能重载
~function()
{
cout << "析构函数调用" << endl;
}
public:
int age;
string name;
};
void test()
{
function p1(10,"lucy");//构造函数在实例化对象时会创建,就是在内存开辟空间时会被调用
//定义在栈区 test生命周期结束后会被销毁 在销毁之前自动调用析构函数
}
int main()
{
test();
return 0;
}
编译运行
构造函数的分类和调用
按参数类型:分为无参构造函数和有参构造函数
按类型分类:普通构造函数和拷贝构造函数(复制构造函数)
拷贝构造:拷贝构造的调用时机:旧对象初始化新对象
其形参必须是引用,但并不限制为const,一般普遍的会加上const限制
如果自定义了一个拷贝构造 那么系统不再提供默认的拷贝构造
#include <iostream>
#include <string.h>
using namespace std;
class function
{
public:
function()
{
cout << "无参构造函数" << endl;
}
function(int init_age,string init_name)
{
age = init_age;
name = init_name;
cout << "有参构造函数" << endl;
}
//拷贝构造的调用时机:旧对象初始化新对象
//如果自定义了一个拷贝构造 那么系统不再提供默认的拷贝构造
function(const function &p)//不能写function p 不能产生新对象
{
//拷贝构造做了简单的值拷贝
age = p.age;
name = p.name;
cout << "拷贝构造" << endl;
}
~function()
{
cout << "析构" << endl;
}
public:
int age;
string name;
};
void test01()
{
//如果人为提供了一个有参或无参构造 系统将不再提供默认的无参构造
function p1;//调用无参构造时 不能加括号
function p2(10,"lucy");
function p3(p2);//调用系统提供的默认拷贝构造
}
void test02()
{
//匿名对象 没有名字 生命周期在当前行
function (10,"tom");
function ();
function p1(20,"ben");
//function p2(p); //匿名对象不能使用括号法调用拷贝函数
}
//显示法调用构造函数
void test03()
{
function p1 = function (10,"tom");//显示法调用有参函数
function p2 = function (p1); //显示法调用拷贝函数
function p3 = function ();//显示法调用无参函数
}
int main()
{
test();
return 0;
}
c++默认构造的函数
默认情况下,c++编译器至少为我们写的类增加 3 个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对类中非静态成员属性简单值拷贝
浅拷贝和深拷贝
浅拷贝:同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况 被称为浅拷贝. 一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动 态内存释放的处理,会导致内存问题。
深拷贝:当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间。
class Person{
public:
Person(char* name,int age){
pName = (char*)malloc(strlen(name) + 1);
strcpy(pName,name);
mAge = age;
}
//增加拷贝构造函数
Person(const Person& person){
pName = (char*)malloc(strlen(person.pName) + 1);//重新开辟空间
strcpy(pName, person.pName);
mAge = person.mAge;
}
~Person(){
if (pName != NULL){
free(pName);
}
}
private:
char* pName;
int mAge;
};
void test(){
Person p1("Edward",30);
//用对象 p1 初始化对象 p2,调用 c++提供的默认拷贝构造函数
Person p2 = p1;
}
多个对象的构造和析构
初始化列表
class Person{public ://传统方式初始化Person(int a,int b,int c){mA = a;mB = b;mC = c;}//初始化列表方式初始化//先声明再根据声明的顺序定义初始化Person( int a, int b, int c):mA(a),mB(b),mC(c){}void PrintPerson(){cout << "mA:" << mA << endl;cout << "mB:" << mB << endl;cout << "mC:" << mC << endl;}private :int mA;int mB;int mC;};
类对象作为成员
类中有多个对象时,构造的顺序是先构造里面的对象,再构造外面的对象
类中有多个对象时,析构的顺序是先析构外面的对象,再析构外面的对象
class Car{
public:
Car(){
cout << "Car 默认构造函数!" << endl;
mName = "大众汽车";
}
Car(string name){
cout << "Car 带参数构造函数!" << endl;
mName = name;
}
~Car(){
cout << "Car 析构函数!" << endl;
}
public:
string mName;
};
//拖拉机
class Tractor{
public:
Tractor(){
cout << "Tractor 默认构造函数!" << endl;
mName = "爬土坡专用拖拉机";
}
Tractor(string name){
cout << "Tractor 带参数构造函数!" << endl;
mName = name;
}
~Tractor(){
cout << "Tractor 析构函数!" << endl;
}
public:
string mName;
};
//人类
class Person{
public:
//类 mCar 不存在合适的构造函数
Person(string name){
mName = name;
}
//初始化列表可以指定调用构造函数
Person(string carName, string tracName, string name) : mTractor(tracName),
mCar(carName), mName(name){
cout << "Person 构造函数!" << endl;
}
#endif
void GoWorkByCar(){
cout << mName << "开着" << mCar.mName << "去上班!" << endl;
}
void GoWorkByTractor(){
cout << mName << "开着" << mTractor.mName << "去上班!" << endl;
}
~Person(){
cout << "Person 析构函数!" << endl;
}
private:
string mName;
Car mCar;
Tractor mTractor;
};
void test(){
//Person person("宝马", "东风拖拉机", "赵四");
Person person("刘能");
person.GoWorkByCar();
person.GoWorkByTractor();
}