4.2 对象的初始化和清理
4.2.1 构造函数和析构函数
对象的初始化非常重要,如果没有初始化,则对象状态是不确定的。 对象的清理也很重要。
构造函数用于对象初始化,析构函数用于对象清理。编译器自动调用,如果不自定义,编译器会实现一个空的函数。
构造函数:成员属性初始化赋值。 析构函数:对象销毁前自动调用。
构造函数语法:类名(){}
无返回值;
函数名称和类名相同;
可以有参数,因此可以重载;
创建对象时自动调用。
析构函数:~类名(){}
无返回值;
函数名称和类名相同,前面加~
;
无参数;
销毁对象前自动调用。
例:
class Person { public: Person(){ cout<<"Person构造函数"<<endl; } ~Person(){ cout<<"Person析构函数"<<endl; } }
4.2.2 构造函数的分类及调用
按参数分类:有参和无参 按类型分类:普通构造和拷贝构造
拷贝构造就是从另一个对象复制一份,所以拷贝构造的参数是一个对象。
调用构造函数方法: 括号法
class Person { public: Person(){ cout<<"Person构造函数Person()"<<endl; } Person(int a){ cout<<"Person构造函数Person(int a)"<<endl; } //拷贝构造函数 Person(const Person &p){ cout<<"Person拷贝构造函数Person(const Person &p)"<<endl; age = p.age } ~Person(){ cout<<"Person析构函数"<<endl; } private: int age; } void test01(){ //括号法 Person p1; Person p2(10); Person p3(p2); //显式法 Person p4 = Person(10); //隐式转换 Person p5 = 10; // 等价于Person p5 = Person(10); Person p6 = p4;// 等价于Person p6 = Person(p4); }
注意事项:
调用默认构造函数用Person p1;
,不能Person p1();
因为,Person p1();
会被当成函数声明。
回顾:函数声明语法return_type funcname(arg_list);
4.2.3 拷贝构造函数的使用
1.使用已有对象初始化一个新的对象 2.值传递方式作为函数参数 3.值方式返回局部对象
e: 2.值传递方式作为函数参数
void doWork(Peron p){ } void test02(){ Person p; doWork(p); }
3.值方式返回局部对象
Person doWork2(){ Person p1; return p1; } void test03(){ Person p = doWork2(); }
4.2.4 构造函数调用规则
C++默认给一个类添加3个函数: 默认构造、默认析构、默认拷贝(属性值拷贝)
如果你自定义了构造函数,编译器就不会再类添加默认构造函数了,但还会提供默认拷贝。
如果自定义了拷贝,则不会提供默认拷贝,且不提供默认构造。
4.2.5 深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝 深拷贝:在堆区申请空间,赋值
浅拷贝的问题:如果变量是指针类型,浅拷贝直接复制内存地址,在析构函数中,会带来重复释放同一块内存的问题。
总结: 如果属性有在堆区开辟的,要自己实现拷贝构造函数,实现深拷贝。
class Person{ public: Person(int age, int height){ m_age = age; m_height = new int(height);//堆区 } Person(const Person & p){ m_age = p.m_age; m_height = new int(*p.m_height); } ~Person(){ if (m_height != NULL){ delete m_height; m_height = NULL; } } int m_age; int* m_height; }
4.2.6 初始化列表
快捷初始化类的属性
语法:构造函数(): 属性1(值1), 属性2(值2)...{}
class Person{ public: Person(int a, int b):m_a(a), m_b(b){ } int m_a; int m_b; };
4.2.7 类对象作为类成员
嵌套。
构造时,先构造成员,再构造自己。 析构时,先析构自己,在析构成员。
4.2.8 静态成员
static成员:
静态成员变量:
所有对象共享
编译阶段分配内存
类内声明,类外初始化
静态成员函数:
所有对象共享
只能访问静态成员
class Person { public: static int m_A;// 类内声明 static void func(){ cout<<"static void func()"<<endl; } }; int Person::m_A = 100; // 类外初始化 int main(){ Person p; p.m_A; Person::m_A; //可以直接用类名访问 }
注意:静态变量也是有访问权限的。