1. 为什么要有构造函数和析构函数
面向对象的思想是从生活中来,手机、车出厂时,是一样的。
这些对象都是被初始化后才上市的,初始化是对象普遍存在的一个状态。
普通方案:
对每个类提供一个 init 函数,对象创建后立即调用 init 函数进行初始化。
这种方案麻烦,并且不易用于对象数组。
所以需要构造函数,对应需要析构函数。
2. 对象的构造
(1)构造函数的定义
C++类可以定义与类名相同的特殊成员函数,此函数为构造函数。
构造函数在定时可以有参数,但无任何返回类型声明。
(2)构造函数的调用
自动调用:对象定义时,C++编译器会自动调用构造函数。
手动调用:程序员可手动调用。
(3)构造函数的分类
- //有参数构造函数的三种调用方法
- class Test
- {
- private:
- int a;
- int b;
- public:
-
- //无参数构造函数
- Test()
- {
- ;
- }
-
- //带参数的构造函数
- Test(int a, int b)
- {
- ;
- }
- //赋值构造函数
- Test(const Test &obj)
- {
- ;
- }
- public:
- void init(int _a, int _b)
- {
- a = _a;
- b = _b;
- }
- };
(4)构造函数的调用
(a)无参构造函数
(b)有参构造函数
- //有参数构造函数的三种调用方法
- class Test5
- {
- private:
- int a;
- public:
- //带参数的构造函数
- Test5(int a)
- {
- printf("\na:%d", a);
- }
- Test5(int a, int b)
- {
- printf("\na:%d b:%d", a, b);
- }
- public:
- };
- int main55()
- {
- Test5 t1(10); //c++编译器默认调用有参构造函数 括号法
- Test5 t2 = (20, 10); //c++编译器默认调用有参构造函数 等号法
- Test5 t3 = Test5(30); //程序员手工调用构造函数 产生了一个对象 直接调用构造构造函数法
- system("pause");
- return 0;
- }
(c)拷贝构造
【1】在函数体内的拷贝构造
注意与拷贝函数区分。
- #include "iostream"
- using namespace std;
- class AA
- {
- public:
- AA() //无参构造函数 默认构造函数
- {
- cout<<"我是无参构造函数,自动被调用了"<<endl;
- }
- AA(int _a) //无参构造函数 默认构造函数
- {
- a = _a;
- cout << "我是有参构造函数" << endl;
- }
- AA(const AA &obj2)
- {
- cout<<"我也是拷贝构造函数,我是通过另外一个对象obj2,来初始化我自己"<<endl;
- a = obj2.a + 10;
- }
- ~AA()
- {
- cout<<"我是析构函数,自动被调用了"<<endl;
- }
- void getA()
- {
- printf("a:%d \n", a);
- }
- protected:
- private:
- int a;
- };
- //单独搭建一个舞台
- void ObjPlay01()
- {
- AA a1; //变量定义
- //赋值构造函数的第一个应用场景
- //用对象1 初始化 对象2
- AA a2 = a1; //定义变量并初始化 //初始化法
- a2 = a1; //用a1来=号给a2 编译器给我们提供的浅copy
- }
- int main()
- {
- ObjPlay01();
- system("pause");
- }

【2】函数传参时的拷贝构造
- #include "iostream"
- using namespace std;
- class Location
- {
- public:
- Location( int xx = 0 , int yy = 0 )
- {
- X = xx ; Y = yy ; cout << "有参构造\n" ;
- }
- Location( const Location & p ) //复制构造函数
- {
- X = p.X ; Y = p.Y ; cout << "拷贝构造" << endl ;
- }
- ~Location()
- {
- cout << X << "," << Y << " 析构" << endl ;
- }
- int GetX () { return X ; } int GetY () { return Y ; }
- private : int X , Y ;
- } ;
- //alt + f8 排版
- void f ( Location p )
- {
- cout << "Funtion:" << p.GetX() << "," << p.GetY() << endl ;
- }
- void mainobjplay()
- {
- Location A ( 1, 2 ) ; //形参是一个元素,函数调用,会执行实参变量初始化形参变量
- f ( A ) ;
- }
- void main()
- {
- mainobjplay();
- system("pause");
- }

【3】函数返回与拷贝构造
注意匿名对象的拷贝构造,和析构。
- //第四个应用场景
- #include "iostream"
- using namespace std;
- class Location
- {
- public:
-
- Location( int xx = 0 , int yy = 0 )
- {
- X = xx ; Y = yy ; cout << "构造函数\n" ;
- }
- Location( const Location & p ) //复制构造函数
- {
- X = p.X ; Y = p.Y ; cout << "拷贝构造" << endl ;
- }
- ~Location()
- {
- cout << X << "," << Y << " 析构函数" << endl ;
- }
- int GetX () { return X ; } int GetY () { return Y ; }
- private : int X , Y ;
- } ;
- //alt + f8 排版
- void f ( Location p )
- {
- cout << "Funtion:" << p.GetX() << "," << p.GetY() << endl ;
- }
- Location g()
- {
- Location A(1, 2);
- return A;
- }
- //对象初始化操作 和 =等号操作 是两个不同的概念
- //匿名对象的去和留,关键看,返回时如何接
- void mainobjplay()
- {
- //若返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构
- Location B;
- B = g(); //用匿名对象 赋值 给B对象,然后匿名对象析构
- //若返回的匿名对象,来初始化另外一个同类型的对象,那么匿名对象会直接转成新的对象
- //Location B = g();
- }
- void main()
- {
- mainobjplay();
- system("pause");
- }

第二种情况:
定义一个新符号去接匿名对象,那么匿名对象会直接转换成新符号对象。
- //第四个应用场景
- #include "iostream"
- using namespace std;
- class Location
- {
- public:
-
- Location( int xx = 0 , int yy = 0 )
- {
- X = xx ; Y = yy ; cout << "构造函数\n" ;
- }
- Location( const Location & p ) //复制构造函数
- {
- X = p.X ; Y = p.Y ; cout << "拷贝构造" << endl ;
- }
- ~Location()
- {
- cout << X << "," << Y << " 析构函数" << endl ;
- }
- int GetX () { return X ; } int GetY () { return Y ; }
- private : int X , Y ;
- } ;
- //alt + f8 排版
- void f ( Location p )
- {
- cout << "Funtion:" << p.GetX() << "," << p.GetY() << endl ;
- }
- Location g()
- {
- Location A(1, 2);
- return A;
- }
- //对象初始化操作 和 =等号操作 是两个不同的概念
- //匿名对象的去和留,关键看,返回时如何接
- void mainobjplay()
- {
- //若返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构
- // Location B;
- //B = g(); //用匿名对象 赋值 给B对象,然后匿名对象析构
- //若返回的匿名对象,来初始化另外一个同类型的对象,那么匿名对象会直接转成新的对象
- Location B = g();
- }
- void main()
- {
- mainobjplay();
- system("pause");
- }

(5)默认构造函数
两个特殊的构造函数:
1)默认无参构造函数
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空。
2)默认拷贝构造函数
当类中没有定义拷贝构造函数时,编译器默认提供一个默认拷贝构造函数,进行浅拷贝。
(6)构造函数调用规则
1)当类中没有定义任何一个构造函数时,c++编译器提供默认无参构造函数和默认拷贝构造函数。
2)当类中定义了拷贝构造函数时,c++编译器不会提供拷贝构造函数。
3)当类中定义了任意非拷贝构造函数,c++编译器不会提供默认无参构造函数。
3. 对象的析构
(1)析构函数的定义
语法:~className()
作用:清理对象
(2)析构函数的调用
对象析构时,C++编译器自动调用。