一、构造函数(constructors)
构造函数命名与类名完全相同,它没有返回值,也不能用void修饰
构造函数不能被直接调用,必须通过创建对象时才会自动调用
1.无参构造函数
默认构造函数必须是无参构造函数
class Test{ public: Test(){} //默认构造函数 } Test t; //默认调用无参构造函数 Test t(); //错误,不能加括号,这表示函数
2.带参构造函数
3.初始化列表构造函数
Test::Test(int a):A(a) { } //等同于下面 Test::Test(int a) { this->A=a; }
4.拷贝构造函数
(1)浅拷贝
//如果没写拷贝构造函数,系统会默认一个拷贝构造函数,把各个成员属性复制过去 class Test{ public: //拷贝构造函数的特点是参数是同类对象 Test(const Test& t){ this->A=t.A; } }; //调用 Test T(t);
(2)深拷贝
注意:当只有类成员带有指针的时候,才有浅拷贝和深拷贝之分。如果只有变量、结构体的话,它们只能拷贝了值过去。
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针
Test(const Test& t){ A=new int(); //另外分配内存给另一个对象,如果同时指向相同的指针地址,会导致析构两次 *A=*(t.A); } Test(const Test& t){ A=new char(20); memcpy(A,t.A,strlen(t.A)); }
二、析构函数(destructors)
析构函数无参数,无返回值,名字与类名相同,前面加个~
三、函数默认初始化
//这个主要是用在有时候调用这个函数需要这个参数,有时候不需要这个参数 void A(int a,int b=0){ }
四.调用顺序
(1)析构函数不加virtual
在构造一个子类对象的时候,先调用基类的构造函数,此时子类成员还没有初始化,虚函数不起作用.再调用子类的构造函数
在析构一个子类对象的时候,先调用子类的析构函数,再调用基类的析构函数
//TestMain.h class A{ public: A(){ cout<<"A+"<<endl; } ~A(){ cout<<"A-"<<endl; } } class B:public A{ public: B(){ cout<<"B+"<<endl; } ~B(){ cout<<"B-"<<endl; } }
//TestMain.cpp int main(){ A* a=new A(); //输出A+ A- delete a; B* b=new B(); //输出A+ B+ B- A- delete b; A* a=new B(); //输出A+ B+ A- delete a; system("pause"); return 0; }
(2)析构函数加virtual
如果父类析构函数加上virtual,那么动态绑定子类的析构函数也会一起进行调用
//TestMain.h class A{ public: A(){ cout<<"A+"<<endl; } ~A(){ cout<<"A-"<<endl; } } class B:public A{ public: B(){ cout<<"B+"<<endl; } ~B(){ cout<<"B-"<<endl; } }
//TestMain.cpp int main(){ A* a=new A(); //输出A+ A- delete a; B* b=new B(); //输出A+ B+ B- A- delete b; A* a=new B(); //输出A+ B+ B- A- delete a; system("pause"); return 0; }