21:C++02:C++基础 - 构造函数、析构函数和拷贝构造函数
1.构造函数
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class Student
{
public:
// 1.构造函数
Student(){// 空参数构造函数
cout << "空参数构造函数"<< endl;
}
// Student(char* name): age(0) { // 一个参数构造函数, 相当于 this->age = 0, age默认值为0
// cout << "一个参数构造函数" << endl;
// this->name = name;
// // this->age = 0;
// }
// Student(char* name): age(0), sex('男'){ // 多个参数有默认值. char sex;
// }
// 2.构造函数相互调用
Student(char* name) :Student(name,0){// 一个参数的构造函数,调用两个参数的构造函数,注意:先会调用两个参数的构造函数,然后才会执行当前构造函数
cout << "一个参数构造函数" << endl;
}
Student(char* name, int age){// 两个参数构造函数
cout << "两个参数构造函数" << endl;
this->name = (char*)malloc(sizeof(char)*100); // 给name开辟100个字节
strcpy(this->name, name);
// this->name = name;
this->age = age;
}
// 3. 析构函数, 如果有在对象内部开辟堆内存,可以在析构函数中释放内存
~Student(){
cout << "析构函数" << endl;
// 临终遗言,对象被回收的时候会被调用
// 释放内存
free(this->name);
this->name = NULL;
}
// 4.拷贝构造函数,对象会有一个默认的拷贝构造函数,用来对象之间的赋值
Student(const Student& stu){// 常量的引用
cout << "拷贝构造函数" << endl;
// this->name = stu.name;// 浅拷贝
// 如果动态开辟内存,一定要采用深拷贝
this->name = (char*)malloc(sizeof(char)* 100);
strcpy(this->name, stu.name); // 名字拷贝到开辟的内存中
this->age = stu.age;
}
// 属性声明
private:
int age;
char* name;
public:
int getAge(){
return this->age;
}
char* getName(){
return this->name;
}
void setAge(int age){
this->age = age;
}
void setName(char* name){
this->name = name;
}
};
void main(){
// Student stu;// 1. 默认调用空参的构造函数
// stu.setAge(24);
// stu.setName("Darren");
// Student stu("Darren",24); // 2. 调用两个参数的构造函数
// cout << stu.getName() << " , " << stu.getAge() << endl; // 使用·访问
// 3. 用 new 关键字,返回的是一个 Student 的一级指针地址,要使用箭头访问
// Student *stu = new Student("Darren",24);
// 4. 用 malloc 的方式,并没有调用空参的构造函数。也没调用别的构造函数。
// Student *stu = (Student*)malloc(sizeof(Student));
// stu->setAge(24);
// stu->setName("Darren");
// 构造函数相互调用: 两个参数构造函数--> 一个参数构造函数
Student *stu = new Student("Darren");
cout << stu -> getName() << " , " << stu->getAge() << endl;
delete(stu); // new的对象,使用delete释放。 【free对象,不会调用析构函数】
getchar();
}
2.析构函数:以‘~’波浪线符号开头。
析构函数只能有一个,且不能有任何输入参数。构造函数可以有N个。
如果有在对象内部开辟堆内存,可以在析构函数中释放内存
相当于对象的临终遗言,对象回收的时候会被调用,一般在这里释放内存。做对象的善后处理。
Java对象的,被回收会调用finalize()方法。
// 3. 析构函数, 如果有在对象的内部开辟 堆内存,可以在析构函数中释放内存
~Student(){
cout << "析构函数" << endl;
// 临终遗言,对象被回收的时候会被调用
// 释放内存
free(this->name);
this->name = NULL;
}
Java 面试题:finalize,finally,final 之间的区别。
finalize:垃圾回收机制,回收该对象时会调用的对象。相当于析构函数。
回收之前会调用这个方法,然后把你所有的回收对象加入到一个Queue中,然后一个个去回收,
可以在这个方法里面,拉活一个对象。
finally:
final:
3. malloc,free,new,delete 的区别。
malloc,new。都是开辟内存和使用
都是开辟和释放内存有关。C++ 里面新增了new 和 delete关键字。
malloc/free 他们是一套,不会去调用构造函数和析构函数;
new/delete 它们是一套,会调用构造函数和析构函数。new的对象,一定要delete释放内存(free无效)。
要成对使用malloc/free, 或 new/delete.
void main(){
// Student stu;// 栈中开辟内存
// malloc、free、 new、delete 都是开辟和释放内存有关。
// 1. malloc/free 他们是一套, new/delete 它们也是配套
// 2. malloc/free 不会去调用构造函数和析构函数
// Student *stu = (Student*)malloc(sizeof(Student));
// free(stu);
// 3. new/delete 会调用构造函数和析构函数,它们是一套。
// Student *stu = new Student(); // 调用构造函数
// delete(stu); // 调用析构函数
// 4. 如果用了 new ,那么一定要记得 delete(释放内存)
getchar();
}
4.拷贝构造函数 符号‘=’
// 4.拷贝构造函数,对象会有一个默认的拷贝构造函数,用来对象之间的赋值
Student(const Student& stu){ // 常量的引用: 一块内存的别名
cout << "拷贝构造函数" << endl;
// this->name = stu.name;// 浅拷贝。让新的指针指向它。
// **** 【深拷贝】:如果动态开辟内存,一定要采用深拷贝,否则会出现问题(多次析构 释放name会报错)
this->name = (char*)malloc(sizeof(char)* 100);
strcpy(this->name, stu.name); // 名字拷贝到开辟的内存中
this->age = stu.age;
}
struct Person {
int age;
char* name;
};
void main(){
Person person1 = {24,"Darren"};
Person person2 = person1; // = 是赋值,把里面所有定义的属性赋值了一遍,c/c++ 编译器帮我们做的
cout << &person1 << " , " << &person2 << endl; // 两个地址不一样,两个不同的结构体对象。
cout << person2.name << " , " << person2.age << endl; // 但是person2,有person1的所有值。
getchar();
}
void main(){
Student *stu1 = new Student("Darren",24);
Student *stu2 = stu1; // 指针复制然后赋值,没有涉及拷贝构造。
stu2->setAge(26);
cout << stu1->getName() << " , " << stu1->getAge() << endl;
getchar();
}
Student getStudent(char* name){
Student stu(name);// 栈 ,方法执行完,这个对象就会被回收,但是发现调用了拷贝构造函数,析构函数
cout << &stu << endl; // 打印对象地址
return stu;// 会返回一个新的 Student 对象,而栈内开辟中的 stu 是会被回收的.
}
void printStudent(Student stu){// stu 是该方法栈中一个新的对象,拷贝构造函数赋值,方法执行完会调用析构函数
cout << stu.getName() << " , " << stu.getAge() << endl; // 执行完,会调用析构函数,释放栈中的内存。
}
void main3(){
// 1. 第一种场景:= 会调用拷贝构造函数
// Student stu1("Darren", 24); // 新建对象stu1
// 对象拷贝函数,用来对象之间的赋值。并没有走对象拷贝函数
// Student stu2 = stu1; // = 是赋值,把里面所有定义的属性赋值,c/c++ 编译器帮我们做的,其实会调用对象的拷贝构造
// 上面调用:两个参数的构造函数,拷贝构造函数
// Student stu2;// 声明变量,同时开辟变量栈内存
// stu2 = stu1; // 注意:这个不会去调用拷贝构造函数,但是会赋值 与c 的类似
// 2. 第二种场景:作为参数返回的时候会调用拷贝构造函数
// Student stu = getStudent("Jack");
// cout << &stu << endl; // 打印对象地址,与getStudent()里面的对象地址不是同一个。不是同一个对象。
// 3. 第三种场景:作为参数传递的时候会调用拷贝构造函数,将对象拷贝一遍。
// Student stu("Darren", 24); // 两个参数构造函数-->拷贝构造函数赋值。
// printStudent(stu);
// 知识的补充:name属性 二次析构的释放,就会有问题。所以 需要使用深拷贝。
Student stu = getStudent("Jack");
// cout << stu.getName() << " , " << stu.getAge() << endl;
printStudent(stu);
getchar();
}
有点奋斗目标,有点理想。
网友评论