一. 构造函数的作用
- 当一个类对象在被创建的时候,编译系统对象分配内存空间,并且自动调用构造函数,由构造函数完成成员的初始化工作.所以构造函数的作用一般是用来初始化对象的数据成员.
- 如果代码里没有显示的定义构造函数,则编译器会自动创建默认的构造函数,以及默认的拷贝构造函数.
默认的构造函数就是一个空实现,默认的拷贝构造函数是简单的属性赋值操作 - 如果显示的定义了构造函数,但是没有定义拷贝构造函数,编译器还是会创建一个默认的拷贝构造函数.作用就是将传递进来的对象的所有数据成员拷贝给正在创建的对象.
二.构造函数的分类
- 无参构造函数(如果用户没有提供任何的构造函数,则系统编译器会默认创建一个无参构造,就是一个空实现)
- 带默认值的构造函数
- 有参(无默认值)的构造函数
- 拷贝构造函数.(如果用户没有定义拷贝构造函数,则编译器会自动创建一个拷贝构造函数)
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person()
{
cout << "Person() 无参构造被调用!" << endl;
}
Person(string name, int age) :m_Name(name), m_Age(age)
{
cout << "Person()的有参构造函数被调用!" << endl;
}
Person(const Person &p)
{
m_Name = p.m_Name;
m_Age = p.m_Age;
cout << "Person()的拷贝构造函数被调用!" << endl;
}
~Person()
{
cout << "Person() 的析构函数被调用!" << endl;
}
private:
string m_Name;
int m_Age = 0;
};
void test_person()
{
Person p1;
Person p2 = Person("Fioman", 18);
Person p3(p2);
}
int main()
{
test_person();
system("pause");
return 0;
}
- 运行结果:
三.拷贝构造函数
拷贝构造函数是一种特殊的构造函数,一般有一个形参,常用const修饰是对该类型的引用. 拷贝函数的调用时机
- 使用已经存在的对象创建初始化一个新对象.
- 值传递的方式给函数参数传值
- 值方式返回局部对象
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person()
{
cout << "Person()的无参构造被调用!" << endl;
}
Person(string name,int age):mName(name),mAge(age)
{
cout << "Person的有参构造函数被调用!" << endl;
}
Person(const Person &p)
{
mName = p.mName;
mAge = p.mAge;
cout << "Person的拷贝构造函数被调用!" << endl;
}
~Person()
{
cout << "Person()的析构函数被调用!" << endl;
}
string getName(void)
{
return mName;
}
int getAge(void)
{
return mAge;
}
private:
string mName;
int mAge = 0;
};
void test_copy_01(void)
{
Person p1("Fioman", 18);
Person p2(p1);
}
void doWork_01(Person p)
{
}
void test_copy_02(void)
{
doWork_01(Person("Fioman", 18));
}
Person doWork_02(void)
{
Person ret = Person("返回对象", 18);
return ret;
}
void test_copy_03(void)
{
Person p;
p = doWork_02();
}
int main()
{
test_copy_01();
system("pause");
return 0;
}
四. 浅拷贝和深拷贝
何为浅拷贝
将原对象中每一个成员字段的值都拷贝到新对象中.这对于普通变量来说没有问题,但是对于指针类型的变量就有问题.因为指针所指向的内存都是动态分配的,并不会自动得到拷贝.这导致原对象和新对象中的字段,全部指向同一块动态分配的内存.
哪些情况下会执行浅拷贝
- 系统创建的默认拷贝构造函数
- 系统默认的赋值运算符
浅拷贝引发的问题
- 如果对象的成员没有指针变量,浅拷贝是没有问题的.但是一旦有了指针变量.指针变量实际上存储的是另一个变量的地址,浅拷贝只是将这个地址拷贝给新对象,并没有给该地址上存储的变量开辟空间并拷贝,所以如果出现原对象已经将该地址释放了,新对象在析构的时候,会再释放一次,造成重复释放同一块内存.
- 两个指针指向同一个内存空间,任意一个指针对该内存进行操作,都会影响另外一个指针.
#include <iostream>
#include<string>
using namespace std;
class Person
{
public:
Person()
{
cout << "默认的无参构造函数被调用!" << endl;
}
Person(string name,int age)
{
mAge = new int(age);
cout << "Person()的有参构造被调用!" << endl;
}
Person(const Person &p)
{
mName = p.mName;
mAge = p.mAge;
cout << "拷贝构造函数被调用!" << endl;
}
~Person()
{
if (mAge != nullptr)
{
delete mAge;
mAge = nullptr;
}
cout << "析构函数被调用,释放指针!" << endl;
}
private:
string mName;
int *mAge = nullptr;
};
void test_shallow_copy(void)
{
Person p1("Fioman", 12);
Person p2(p1);
}
int main()
{
test_shallow_copy();
system("pause");
return 0;
}
解析:
代码运行的过程中会报错,因为指针变量mAge ,被释放了两次.
何为深拷贝
深拷贝是指不仅拷贝原对象中的每一个字段,而且将动态分配给该字段的内存内容一并拷贝过来. 所有在面对有指针属性的变量的时候,我们必须编写拷贝函数,并重载运算符.深拷贝会在堆中另外申请空间来存储数据,从而解决指针悬挂的问题.
#include <iostream>
#include<string>
using namespace std;
class Person
{
public:
Person()
{
cout << "默认的无参构造函数被调用!" << endl;
}
Person(string name, int age)
{
mAge = new int(age);
cout << "Person()的有参构造被调用!" << endl;
}
Person(const Person &p)
{
mName = p.mName;
mAge = new int(*p.mAge);
cout << "拷贝构造函数被调用!" << endl;
}
~Person()
{
if (mAge != nullptr)
{
delete mAge;
mAge = nullptr;
}
cout << "析构函数被调用,释放指针!" << endl;
}
private:
string mName;
int *mAge = nullptr;
};
void test_shallow_copy(void)
{
Person p1("Fioman", 12);
Person p2(p1);
}
int main()
{
test_shallow_copy();
system("pause");
return 0;
}
|