C++学习 --- 类和对象之对象的初始化和清理
二、对象的初始化和清理
1、构造函数和析构函数
#include <iostream> #include <string> using namespace std; //对象初始化和清理 //1.构造函数 进行初始化操作 class Person { public: //1、构造函数: /* 1.没有返回值 不写void 2.函数名与类名相同 3.构造函数可以有参数,可以发生重载 4.创建对象的时候,构造函数会自动调用,而且之调用一次 */ Person() { cout << " Person构造函数的调用 " << endl; } //2、析构函数 进行清理的操作 /* 1.没有返回值,不写void 2.函数名和类名相同 在名称前加~ 3.析构函数不可以有参数的,不可以发生重载 4.对象在销毁前 会自动调用析构函数,而且只会调用一次 */ ~Person() { cout << " Person 析构函数调用 " << endl; } }; //构造和析构都是必须有的实现 //如果自己不提供,编译器会提供一个空实现的构造和析构 void test01(){ Person p; //栈上的数据,test01执行完毕后,释放这个对象 } int main() { //test01(); Person p; system("pause"); return 0; }
2、构造函数的分类及调用
#include <iostream> #include <string> using namespace std; //构造函数的分类及调用 //分类 //按照参数分类 无参(默认)构造和有参构造 //按照类型分类 普通构造函数和拷贝构造函数 class Person { public: Person() { cout << " Person 的无参构造函数调用 " << endl; } Person(int a) { age = a; cout << " Person 的有参构造函数调用 " << endl; } //拷构造函数 Person(const Person &p) { //将传入的对象属性拷贝到当前对象上 age = p.age; cout << " Person 的拷贝构造函数调用 " << endl; } ~Person() { cout << " Person 的析构函数调用 " << endl; } int age; }; //调用 void test01() { //1.括号法,常用 Person p1; //默认构造函数调用 Person p2(10); //有参构造函数 Person p3(p2); //拷贝构造函数 cout << "p2 的年龄 :" << p2.age << endl; cout << "p3 的年龄 :" << p3.age << endl; //注意事项1 //调用默认构造函数的时候,不要加() //当写了()之后就不会创建对象了 //下面这行代码,编译器会认为是函数声明,不会认为在创建对象 //Person pX(); //无参数,返回值是Person //2.显示法 Person p4; //无参构造函数 Person p5 = Person(20); //有参构造函数 Person p6 = Person(p5); //拷贝构造函数 //匿名对象,特点:当前行执行结束后,系统会立即回收掉匿名对象 Person(10); cout << "aaa" << endl; //注意事项2 //不要利用拷贝构造函数,初始化匿名对象 //编译器会认为Person(p4) 等价于 Person p4,p4是对象的声明; //编译器报错为 Person p4 重定义 //Person(p4); //3.隐式转换法 Person p7 = 15; //相当于 Person p7 = Person(15); Person p8 = p7; //拷贝构造 } int main() { test01(); system("pause"); return 0; }
3、拷贝构造函数调用时机
#include <iostream> #include <string> using namespace std; //拷贝构造函数的调用时机 //1.使用一个已经创建完毕的对象来初始化一个新对象 //2.值传递的方式给函数参数传值 //3.用值的方式返回局部的对象 class Person { public: Person() { cout << "Person 的无参(默认)构造函数调用 " << endl; } Person(int age) { m_Age = age; cout << "Person 的有参构造函数调用 " << endl; } Person(const Person & p) { m_Age = p.m_Age; cout << "Person 的拷贝构造函数调用 " << endl; } ~Person() { cout << "Person 的析构函数调用 " << endl; } int m_Age; }; //1.使用一个已经创建完毕的对象来初始化一个新对象 void test01() { Person p1(20); //无参构造函数调用 Person p2(p1); //拷贝构造函数调用 cout << "p2的年龄:" << p2.m_Age << endl; } //2.值传递的方式给函数参数传值 void doWork(Person p) { } void test02() { Person p; //无参构造函数调用 doWork(p); //拷贝构造函数调用 } //3.用值的方式返回局部的对象 Person doWork2() { Person p1; cout << (int *)&p1 << endl; return p1; } void test03() { Person p = doWork2(); //拷贝构造函数调用 cout << (int *)&p << endl; } int main() { //test01(); //test02(); test03(); system("pause"); return 0; }
4、构造函数的调用规则
#include <iostream> #include <string> using namespace std; //构造函数的调用规则 //1.创建一个类,c++编译器会给每个类都添加至少3个函数 //默认构造 (空实现) //析构函数 (空实现) //拷贝构造 (值拷贝) //2. //如果我们写了 有参构造函数,编译器就不在提供默认构造(不能使用),依然提供拷贝构造(能使用) //如果我们写了拷贝构造函数,编译器就不再提供其他普通构造函数了 class Person { public: /*Person() { cout << "Person 的 无参(默认)构造函数调用" << endl; }*/ Person(int age) { m_Age = age; cout << "Person 的 有参构造函数调用" << endl; } //Person(const Person & p) { // m_Age = p.m_Age; // cout << "Person 的 拷贝构造函数调用" << endl; //} ~Person() { cout << "Person 的 析构函数调用" << endl; } int m_Age; }; //void test01(){ // Person p; // p.m_Age = 18; // // Person p2(p); // cout << "p2 的年龄:" << p2.m_Age << endl; //} void test02() { Person p(20); Person p2(p); cout << "p2 的年龄:" << p2.m_Age << endl; } int main() { //test01(); test02(); system("pause"); return 0; }
5、深拷贝与浅拷贝
编译器提供的拷贝构造函数是浅拷贝,对于有指针类型的成员,在调用浅拷贝构造函数和析构函数后有重复释放指针的问题,出现异常。需要自己实现深拷贝构造函数重新开辟堆区空间解决此问题。
如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题
#include <iostream> #include <string> using namespace std; class Person { public: Person() { cout << "Person 的默认(无参)构造函数调用 " << endl; } Person(int age,int height) { m_Age = age; m_Height = new int(height); cout << "Person 的有参构造函数调用 " << endl; } //自己实现拷贝构造函数解决浅拷贝带来的问题 Person(const Person &p) { cout << "Person 的拷贝构造函数调用 " << endl; m_Age = p.m_Age; //编译器默认实现的部分 //原来的浅拷贝 //m_Height = p.m_Height; //编译器默认实现的部分 //深拷贝 m_Height = new int(*p.m_Height); } //析构规则,先进后出。先定义的变量最后调用析构 ~Person() { //堆区开辟的数据做释放操作 if (m_Height != NULL) { delete m_Height; m_Height = NULL; } cout << "Person 的析构函数调用 " << endl; } int m_Age; int * m_Height; //指针表示身高,开辟在堆区 }; void test01() { Person p1(18,160); cout << "p1 的年龄: " << p1.m_Age << endl; cout << "p1 的身高: " << *p1.m_Height << endl; Person p2(p1); //编译器帮助做了浅拷贝,赋值操作 cout << "p2 的年龄: " << p2.m_Age << endl; cout << "p2 的身高: " << *p2.m_Height << endl; //浅拷贝带来的问题是,堆区的内存重复释放。异常 //解决方式:利用深拷贝 } int main() { test01(); system("pause"); return 0; }