拷贝构造函数
依然使用Student作为例子展开,其中CStudent(CStudent& stud) 就是拷贝构造函数,可以实现在使用类去初始话一个对象时,用同一个类的另外一个对象初始化。
class CStudent
{
public:
char *p_name;
char sex;
int num;
int age;
CStudent(){};
CStudent(char* pname, char t_sex, int t_num, int t_age) :sex(t_sex), num(t_num), age(t_age)
{
p_name = NULL;
int n_len = 0;
if (pname)
{
n_len = strlen(pname);
}
if (n_len > 0)
{
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, pname);
}
}
CStudent(CStudent& stud)
{
strcpy(p_name, stud.p_name);
num = stud.num;
age = stud.age;
}
~CStudent();
};
异常报错
在拷贝构造函数,加入对对应的析构函数后,程序如下所示,运行以下程序。
#include <iostream>
#include <string>
using namespace std;
class CStudent
{
public:
char *p_name;
char sex;
int num;
int age;
CStudent(){};
CStudent(char* pname, char t_sex, int t_num, int t_age) :sex(t_sex), num(t_num), age(t_age)
{
p_name = NULL;
int n_len = 0;
if (pname)
{
n_len = strlen(pname);
}
if (n_len > 0)
{
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, pname);
}
}
CStudent(CStudent& stud)
{
strcpy(p_name, stud.p_name);
num = stud.num;
age = stud.age;
}
~CStudent();
};
CStudent::~CStudent()
{
if (p_name)
{
delete[] p_name;
p_name = NULL;
}
}
void test()
{
CStudent stud_1 = { "zhangsan",'m', 1001, 20 };
CStudent stud_2(stud_1);
}
int main(int argc, char* argv[])
{
test();
return 0;
}
可能会出现以下报错
HEAP CORRUPTION DETECTED:before Free block(#0) at 0x008A4930.CRT detected that the application wrote to memory before start of heap buffer.
_BLOCK_TYPE_IS_VALID(PhEAD->nBlockUse
由于出现问题,程序停止正常工作。windows将关闭程序,并会在有可用的解决方案时通知你。
原因:拷贝构造函数的p_name指针和源构造函数的p_name指针指向的是同一块内存,当第一次析构之后~CStudent已经完成析构,但是由于有拷贝构造函数的p_name指针也需要析构,就会出现异常。
解决方案
解决方案就是在构建拷贝构造函数时,需要为新的指针开辟内存空间,防止两个指针指向同一块内存空间。
#include <iostream>
#include <string>
using namespace std;
class CStudent
{
public:
char *p_name;
char sex;
int num;
int age;
CStudent(){};
CStudent(char* pname, char t_sex, int t_num, int t_age) :sex(t_sex), num(t_num), age(t_age)
{
p_name = NULL;
int n_len = 0;
if (pname)
{
n_len = strlen(pname);
}
if (n_len > 0)
{
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, pname);
}
}
CStudent(const CStudent& stud)
{
int n_len = 0;
n_len = strlen(stud.p_name);
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, stud.p_name);
num = stud.num;
age = stud.age;
}
~CStudent();
};
CStudent::~CStudent()
{
if (p_name)
{
delete[] p_name;
p_name = NULL;
}
}
void test()
{
CStudent stud_1 = { "zhangsan",'m', 1001, 20 };
CStudent stud_2(stud_1);
}
int main(int argc, char* argv[])
{
test();
return 0;
}
上面是使用重载构造函数解决问题,如果想使用以下命令去实现初始化
CStudent stud_2;
stud_2 = stud_1;
仍然使用上诉程序是会报和之前一样的错误,因为之前的幅值是函数赋值,现在是命令符赋值,这里就需要使用重载运算符。
CStudent& operator=(const CStudent& stud)
{
int n_len = 0;
n_len = strlen(stud.p_name);
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, stud.p_name);
num = stud.num;
age = stud.age;
return *this;
}
完整代码如下:
#include <iostream>
#include <string>
using namespace std;
class CStudent
{
public:
char *p_name;
char sex;
int num;
int age;
static int master;
CStudent(){};
CStudent(char* pname, char t_sex, int t_num, int t_age) :sex(t_sex), num(t_num), age(t_age)
{
p_name = NULL;
int n_len = 0;
if (pname)
{
n_len = strlen(pname);
}
if (n_len > 0)
{
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, pname);
}
}
CStudent(const CStudent& stud)
{
int n_len = 0;
n_len = strlen(stud.p_name);
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, stud.p_name);
num = stud.num;
age = stud.age;
}
CStudent& operator=(const CStudent& stud)
{
int n_len = 0;
n_len = strlen(stud.p_name);
p_name = new char[n_len + 1];
memset(p_name, 0, n_len + 1);
strcpy(p_name, stud.p_name);
num = stud.num;
age = stud.age;
return *this;
}
~CStudent();
};
CStudent::~CStudent()
{
if (p_name)
{
delete[] p_name;
p_name = NULL;
}
}
int CStudent::master = 0;
void test()
{
CStudent stud_1 = { "zhangsan",'m', 1001, 20 };
CStudent stud_2;
stud_2 = stud_1;
}
int main(int argc, char* argv[])
{
test();
return 0;
}