C++是面向对象的编程语言呢,具有类class,类的初始化就需要调用类的构造函数,默认调用类的无参构造函数,如果重写了类的构造函数,会覆盖类的默认构造函数。
构造函数
构造函数是一种特殊的成员函数,除具有一般成员函数的特性外,还具有如下特殊性质:
1)、构造函数的函数名必须与其类名相同;
2)、不包含任何返回类型,也不能写成void类型;
3)、一个类可以有多个构造函数(即构造函数重载),也可以没有构造函数(在这种情况下,系统会自动为类创建一个默认构造函数,该构造函数无参数4) 、构造函数可以有参数,也可以没有参数;);
4)、在创建对象时,系统会自动调用构造函数(例:执行 Person abc; 语句时就自动调用了构造函数),且只调用一次;
5)、用new运算符动态创建对象时也会自动调用构造函数;
6)、通常,设为public类型。
class Student
{
public:
void mprintf(){
cout << "name:" << name << "--------" << "age:" << age << endl;
}
//覆盖该类的默认构造函数
Student(char*name, int age){
this->name = name;
this->age = age;
}
private:
char* name;
int age;
};
void main(){
Student s("xiaoMing",15);
s.mprintf();
getchar();
}

析构函数
析构函数存在的必要性:
a)、如果构造函数中使用了new 命令申请了堆空间,在对象撤消时,就要用delete命令归还对象所占空间。否则,造成内存泄漏。
b)、退出程序时,进行文件内容检查,提示存盘操作 。
析构函数是一种特殊的成员函数,除具有一般成员函数的特性外,还具有如下特性:
1)、析构函数的函数名必须与其类名相同,不能指定返回类型,也不能使用void。为了能与构造函数相区别,要在函数名前加~(波浪符);
2)、析构函数没有参数,一个类中只能拥有一个析构函数,所以析构函数不能重载。定义格式为: ~类名(){ 函数体 } ;
3)、如果程序员没有定义类的析构函数,系统会自动为类创建一个默认析构函数,形式为: ~类名(){ };
4)、通常为public类型,系统在撤消对象时,自动调用析构函数。也允许显式调用;
5)、用delete运算符删除对象时也会自动调用析构函数 。
class Student
{
public:
void mprintf(){
cout << "name:" << name << "--------" << "age:" << age << endl;
}
//覆盖该类的默认构造函数
Student(char*name, int age){
this->name = name;
this->age = age;
cout << "构造函数" << endl;
}
//析构函数
~Student(){
cout << "析构函数" << endl;
}
private:
char* name;
int age;
};
void func(){
Student s("xiaoMing", 15);
s.mprintf();
}
void main(){
func();
getchar();
}

当对象要被系统释放时,析构函数被调用,在析构函数中可以做一些善后处理处理的工作,如释放内存。
拷贝构造函数
概念:用一个已有的对象来初始化一个被创建的同类对象,是一种特殊的成员函数。
声明的一般格式: 类名(类名 & 对象名);
利用拷贝构造函数可以实现同类对象的数据传递, 即对象的“克隆”。(注意:与对象赋值的不同) (相对于拷贝构造函数,前面介绍的构造函数被称为普通构造函数)
拷贝构造函数的性质 :
1)、函数名必须与类名相同,并且不指定返回类型;
2)、只有一个参数,是同类的对象的引用;
3)、每一个类中都必须有一个拷贝构造函数。如果类中没有声明拷贝构造函数,编译器就会自动生成一个具有上述形式的公有的拷贝构造函数。
拷贝构造函数被调用的场景:
1)、声明时赋值 Student s1 = s;
2)、作为参数传入,实参给形参赋值 func(s);
3)、作为函数返回值返回,给变量初始化赋值 Student s1 = func(s);
浅拷贝和深拷贝
如果在类的定义里没有提供拷贝构造函数,C++会提供一个默认的拷贝构造函数; 默认拷贝构造函数的拷贝方式是各成员逐一复制,这称为是浅拷贝; 在某些情况下,浅拷贝会产生问题,例如:当一个类在它的构造函数动态分配了内存资源,浅拷贝只会复制该资源的地址,而不会为新建的对象重新分配一个资源,因此,会出现多个对象指向同一个堆空间的地址的现象。
浅拷贝也就是值拷贝:
class Student
{
public:
void mprintf(){
cout << "name:" << name << "--------" << "age:" << age << endl;
}
//覆盖该类的默认构造函数
Student(char*name, int age){
this->name = name;
this->age = age;
cout << "构造函数" << endl;
}
//默认拷贝构造函数,就是值拷贝
Student(const Student &obj){
this->name = obj.name;
this->age = obj.age;
cout << "拷贝构造函数" << endl;
}
//析构函数
~Student(){
cout << "析构函数" << endl;
}
private:
char* name;
int age;
};
void func(Student s){
s.mprintf();
}
void main(){
Student s("xiaoMing", 15);
func(s);
getchar();
}

浅拷贝(值拷贝)问题
class Student
{
public:
void mprintf(){
cout << "name:" << name << "--------" << "age:" << age << endl;
}
//覆盖该类的默认构造函数
Student(char*name, int age){
this->name = (char*)malloc(100);
strcpy(this->name, name);
this->age = age;
cout << "构造函数" << endl;
}
////默认拷贝构造函数,就是值拷贝
//Student(const Student &obj){
// this->name = obj.name;
// this->age = obj.age;
// cout << "拷贝构造函数" << endl;
//}
//析构函数
~Student(){
cout << "析构函数" << endl;
free(this->name);
}
private:
char* name;
int age;
};
void func(){
Student s("xiaoMing", 15);
Student s1 = s;
s1.mprintf();
}
void main(){
func();
getchar();
}

以上就是因为浅拷贝导致中止。错误的原因:两个对象的指针指向同一存储地址,析构时要求释放两次。
解决问题的方法:深拷贝
在拷贝构造函数中,显式地为每个拷贝对象申请资料,这种拷贝构造方式称为深拷贝。
class Student
{
public:
void mprintf(){
cout << "name:" << name << "--------" << "age:" << age << endl;
}
//覆盖该类的默认构造函数
Student(char*name, int age){
this->name = (char*)malloc(100);
strcpy(this->name, name);
this->age = age;
cout << "构造函数" << endl;
}
//深拷贝
Student(const Student &obj){
//复制name属性
int len = strlen(obj.name);
this->name = (char*)malloc(len + 1);
strcpy(this->name, obj.name);
this->age = obj.age;
cout << "拷贝构造函数" << endl;
}
//析构函数
~Student(){
cout << "析构函数" << endl;
free(this->name);
}
private:
char* name;
int age;
};
void func(){
Student s("xiaoMing", 15);
Student s1 = s;
s1.mprintf();
}
void main(){
func();
getchar();
}
