有关构造函数
1构造函数定义及调用
1)C++中的类可以定义与类名相同的特殊成员函数,这种与类名相同的成员函数叫做构造函数;
2)构造函数在定义时可以有参数;
3)没有任何返回类型的声明。
2构造函数的调用
自动调用:一般情况下C++编译器会自动调用构造函数
手动调用:在一些情况下则需要手工调用构造函数
有关析构函数
析构函数定义及调用
1)C++中的类可以定义一个特殊的成员函数清理对象,这个特殊的成员函数叫做析构函数
语法:~ClassName()
2)析构函数没有参数也没有任何返回类型的声明
3)析构函数在对象销毁时自动被调用
4)析构函数调用机制
C++编译器自动调用
先创建的对象 后释放
Q对象销毁是发生在什么时候?
A对象的析构函数在的对象销毁前被调用,对象何时销毁也与其作用域有关。
例如,全局对象是在程序运行结束时销毁,自动对象是在离开其搜索作用域时销毁,而动态对象则是在使用delete运算符时销毁。
#include <iostream> using namespace std; class Test2 { public: //无参数构造函数 Test2() { m_a = 0; m_b = 0; cout<<"无参数构造函数"<<endl; } //有参数构造函数 Test2(int a) { m_a = a; m_b = 0; } Test2(int a, int b) { m_a = a; m_b = b; cout<<"有参数构造函数"<<endl; } //赋值构造函数 (copy构造函数) Test2(const Test2& obj) { cout<<"我也是构造函数 " <<endl; } public: void printT() { cout<<"普通成员函数"<<endl; } private: int m_a; int m_b; }; int main01() { Test2 t1; //调用无参数构造函数 cout<<"hello..."<<endl; return 0; } //调用 调用有参数构造函数 3 int main(void) { //1括号法 Test2 t1(1, 2); //调用参数构造函数 c++编译器自动的调用构造函数 t1.printT(); // 2 =号法[但这是一个很鸡肋的用法] Test2 t2 = (3, 4); // = c++对等号符 功能增强 c++编译器自动的调用构造函数 //对象的初始化 和 对象的赋值 是两个不同的概念 //3 对象的初始化 Test2 t4 = Test2(1, 2); //匿名对象 t1 = t4; //把t4 copy给 t1 //赋值操作 //4 赋值构造函数 (copy构造函数) Test2 t5 = Test2(t1); //等价于Test2 t5(t1); 等价于 Test2 t5 = t1; //☆ Test2 t5 = Test2(t1);是程序员手工的调用构造函数 cout<<"hello..."<<endl; return 0; } /*============================================== END File ==============================================*/
有参数构造函数
普通成员函数
有参数构造函数
我也是构造函数
hello...
赋值构造函数的4种应用场景
这是初始化的两种; Test t2 = t1; Test t2(t1);
第三种是功能函数的形参是一个元素的时候{非指针,非引用},这个时候实参给形参的时候必然调用拷贝构造
第四种是你说的返回,返回一个对象的时候,但这个时候返回的是匿名对象,
如果是初始化,是直接会转换为要初始化的那个对象的,
如果是赋值操作,这个时候确实会调用copy构造,但是这个对象的生命周期只有那么一行,用完立即被析构
#include <iostream> using namespace std; class Test4 { public: Test4() //无参数构造函数 { m_a = 0; m_b = 0; cout<<"无参数构造函数"<<endl; } Test4(int a) { m_a = a; m_b = 0; } Test4(int a, int b) //有参数构造函数 { m_a = a; m_b = b; cout<<"有参数构造函数"<<endl; } Test4(const Test4& obj )//赋值构造函数 (copy构造函数) { cout<<"赋值构造函数 " <<endl; m_b = obj.m_b + 100; m_a = obj.m_a + 100; } public: void printT() { cout<<"普通成员函数"<<endl; cout<<"m_a"<<m_a<<" m_b"<<m_b<<endl; } private: int m_a; int m_b; }; //1 赋值构造函数 用1个对象去初始化另外一个对象 int main(void) { Test4 t0(1, 2); Test4 t1(1, 2); /*赋值操作 和 初始化是两个不同的概念 =的赋值操作 不会调用构造函数 =的初始化操作 会调用构造函数 */ //operator=()//抛砖 t0 = t1; //用t1 给 t0赋值 //第1种调用方法 Test4 t2 = t1; //用t1来初始化 t2 【one】 t2.printT(); //第2种调用方法 Test4 t3(t1); //用t1对象 初始化 t2对象 【two】 t2.printT(); cout<<"hello..."<<endl; return 0; }
[Three]
#include <iostream> using namespace std; class Location { public: Location( int xx = 0 , int yy = 0 ) { X = xx ; Y = yy ; cout << "None Param Constructor Func.\n" ; } //copy构造函数 完成对象的初始化 Location(const Location & obj) //copy构造函数 { cout << "Copy Constructor func.\n" ; X = obj.X; Y = obj.Y; } ~Location() { cout << X << "," << Y << " Object destroyed." << endl ; } int GetX () { return X ; } int GetY () { return Y ; } private: int X , Y ; }; //业务函数 形参是一个元素 void f(Location p) { cout<<"业务函数"<<endl; cout<<p.GetX()<<endl; } void playobj() { Location a(1, 2); Location b = a; cout<<"b对象已经初始化完毕"<<endl; f(b); //实参b传给形参p会调用copy构造函数 } int main() { playobj(); cout<<"hello..."<<endl; return 0; }
None Param Constructor Func.
Copy Constructor func.
b对象已经初始化完毕
Copy Constructor func.
业务函数
1
1,2 Object destroyed.
1,2 Object destroyed.
1,2 Object destroyed.
hello...
[Four]
#include <iostream> #include <cstdio> using namespace std; class Location { public: Location( int xx = 0 , int yy = 0 ) { X = xx ; Y = yy ; cout << "Constructor Object.\n" ; } //copy构造函数 完成对象的初始化 Location(const Location & obj) //copy构造函数 { X = obj.X; Y = obj.Y; } ~Location() { cout << X << "," << Y << " Object destroyed." << endl ; } int GetX () { return X ; } int GetY () { return Y ; } private : int X , Y ; } ; /******************************************************************************************************************* g函数 返回一个元素 结论1 : 函数的返回值是一个元素 (复杂类型的), 返回的是一个新的匿名对象(所以会调用匿名对象类的copy构造函数) 结论2: 有关 匿名对象的去和留 如果用匿名对象 初始化 另外一个同类型的对象, 匿名对象 转成有名对象 如果用匿名对象 赋值给 另外一个同类型的对象, 匿名对象 被析构 你这么写代码,设计编译器的大牛们: 我就给你返回一个新对象(没有名字 匿名对象) *******************************************************************************************************************/ Location g() { Location A(1, 2); return A; } // void objplay2() { g(); } // void objplay3() { //用匿名对象初始化m 此时c++编译器 直接把匿名对转成m;(扶正) 从匿名转成有名字了m Location m = g(); printf("\r\n匿名对象,被扶正,不会析构掉\n"); cout<<m.GetX()<<endl; } void objplay4() { //用匿名对象 赋值给 m2后, 匿名对象被析构 Location m2(1, 2); m2 = g(); printf("\r\n因为用匿名对象=给m2, 匿名对象,被析构\n"); cout<<m2.GetX()<<endl;; } int main(void) { objplay2(); // objplay3(); // objplay4(); cout<<"hello..."<<endl; return 0; }
二个特殊的构造函数
1) 默认无参构造函数
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空
2) 默认拷贝构造函数
当类中没有定义拷贝构造函数时,编译器默认提供一个默认拷贝构造函数,简单的进行成员变量的值复制
1)当类中没有定义任何一个构造函数时, c++编译器会提供默认无参构造函数和默认拷贝构造函数
2)当类中定义了拷贝构造函数时, c++编译器不会提供无参数构造函数
3)当类中定义了任意的非拷贝构造函数(即:当类中提供了有参构造函数或无参构造函数), c++编译器不会提供默认无参构造函数
4 )默认拷贝构造函数成员变量简单赋值
总结:只要你写了构造函数,那么你必须用。
构造析构阶段性总结
1)构造函数是C++中用于初始化对象状态的特殊函数
2)构造函数在对象创建时自动被调用, 在对象离开其作用域时候自动销毁
3)构造函数和普通成员函数都遵循重载规则
4)拷贝构造函数是对象正确初始化的重要保证
5) 必要的时候,必须手工编写拷贝构造函数