总结c++类的构造函数 拷贝构造函数 析构函数 赋值运算符重载的特点以及函数调用顺序
2016-10-18 19:04
597 查看
对 c++类的构造函数 拷贝构造函数 析构函数 赋值运算符重载 相关知识的总结,并附上例子,希望对大家有帮助,有错误大家可以指出来
一 构造函数
1 构造函数: 构造函数时一个特殊的成员函数,用来初始化对象的数据成员,在对象创建时,由编译器自动调用,在对象的生命周期且只调用一次。
定义构造函数的原型的格式: 类名(形参列表);
在类外定义构造函数的格式:类名::类名(形参列表) {}
2 构造函数的特点:
(1)函数名与类名相同;
(2)没有返回值,也不能指定为void类型;
(3)有初始化列表
(2)数据成员在类中定义的顺序就是参数列表中的初始化顺序
类中以下成员必须放在初始化列表中初始化:
(a)引用数据成员 (b) const 数据成员
(c)基类没有显示的构造函数,必须在派生类的构造函数中初始化基类构造函数
(d)类类型成员(该类没有缺省的构造函数) 因为初始化不必调用默认构造函数来初始化,直接调用拷贝构造函数
(4)构造函数可以重载,默认参数只能在原型声明中指定,不能在函数定义中指定。
(5)无参构造函数和带缺省的构造函数都认为是缺省构造函数,并且缺省构造函数只能有一个
(6)构造函数不能用const 修饰
3 构造函数的作用 :构建对象,初始化对象,类型转换
二 拷贝构造函数(特殊的构造函数)
1 只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),创建对象时使用已存在的同类对象来进行初始化,由编译器自动调用
2 特征:(1)是构造函数的重载
(2)它的参数必须是同类类型对象的引用。原因:防止拷贝构造函数无限递归下去
(3)如果没有显示定义,系统会自动合成一个默认的拷贝构造函数。默认的拷贝构造函数会依次拷贝类的数据 成员完成初始化。
3 使用场景:
(1)对象实例化
(2)传值方式作为函数的参数
(3)传值方式作为返回值
Date& FunTest(Date& d)函数调用顺序
[b]Date FunTest(Date d)函数调用顺序
[/b]
[b]
[/b]
[b]Date FunTest(Date d)函数 返回值是无名对象调用顺序
[/b]
[b]
[/b]
私有的拷贝构造函数:防止一个对象不被通过传值方式传递。
三 析构函数
析构函数:与构造函数的功能相反,在对象销毁时,由编译器自动调用,完成类的一些资源清理和汕尾工作。
注意:析构函数的目的是在系统回收对象 内存之前执行结束清理工作,以便内存可被重新用于保存新对象。
2 特性
a 析构函数没有参数没有返回值,函数名是类名前加上`.
b 一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。
c析构函数并不是删除对象,只是做一些清理工作。
d 调用次序与构造函数相反,最先构造的对象最后被析构。
四 赋值运算符重载
c++中,对于任何一个类,如果没有用户自定义的赋值运算符函数,系统会自动的生成一个默认的(默认的完成的数据成员的逐位复制)。特殊情况下:如类中有指针形式就不能直接相互赋值,不然可能造成指针悬挂问题。
注意:(1)赋值运算符不能重载为友元函数,只能重载为一个非静态成员函数。
(2)赋值运算符重载函数不能被继承。
注意 1 在赋值函数为:Date operator=(const Date& d)的情况下
2 在赋值函数为:Date& operator=(const Date&d)的情况下
不同的是没有临时对象的产生,因为operator=返回的是对当前对象的引用,而引用只是别名,而不是构造新对象的
区别拷贝构造函数和赋值操作符重载函数的调用区别
有什么问题,大家可以评论。
一 构造函数
1 构造函数: 构造函数时一个特殊的成员函数,用来初始化对象的数据成员,在对象创建时,由编译器自动调用,在对象的生命周期且只调用一次。
定义构造函数的原型的格式: 类名(形参列表);
在类外定义构造函数的格式:类名::类名(形参列表) {}
class Date //date.h { public: Date(int year, int month, int day); private: int _year; int _month; int _day; }; Date::Date(int year,int month,int day) //date.cpp { // 函数语句 }
2 构造函数的特点:
(1)函数名与类名相同;
(2)没有返回值,也不能指定为void类型;
(3)有初始化列表
public: Date(int year = 1995, int month = 12, int day = 8) :_year(year) ,_month(month) , _day(day) { }初始化顺序:(1)每个成员在初始化列表中只能出现一次
(2)数据成员在类中定义的顺序就是参数列表中的初始化顺序
类中以下成员必须放在初始化列表中初始化:
(a)引用数据成员 (b) const 数据成员
(c)基类没有显示的构造函数,必须在派生类的构造函数中初始化基类构造函数
(d)类类型成员(该类没有缺省的构造函数) 因为初始化不必调用默认构造函数来初始化,直接调用拷贝构造函数
class Food { public: Food(int q = 10) { _quantity = q; cout << "food 构造" << endl; } Food(const Food& f) { _quantity = f._quantity; cout << "food 拷贝构造" << endl; } private: int _quantity; };
(4)构造函数可以重载,默认参数只能在原型声明中指定,不能在函数定义中指定。
(5)无参构造函数和带缺省的构造函数都认为是缺省构造函数,并且缺省构造函数只能有一个
(6)构造函数不能用const 修饰
3 构造函数的作用 :构建对象,初始化对象,类型转换
// 类型转换构造函数,根据一个指定的类型的对象创建一个本类的对象 // 例如:下面将根据一个double类型的对象创建了一个Complex对象 Complex::Complex(double r) { m_real = r; m_imag = 0.0; }
二 拷贝构造函数(特殊的构造函数)
1 只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),创建对象时使用已存在的同类对象来进行初始化,由编译器自动调用
2 特征:(1)是构造函数的重载
(2)它的参数必须是同类类型对象的引用。原因:防止拷贝构造函数无限递归下去
(3)如果没有显示定义,系统会自动合成一个默认的拷贝构造函数。默认的拷贝构造函数会依次拷贝类的数据 成员完成初始化。
3 使用场景:
class Date { public: Date(int year = 1995,int month = 12,int day = 8) // 构造函数 :_year(year) , _month(month) , _day(day) { cout << "date()构造函数"<< this << endl; } Date(const Date& d)// 拷贝构造函数 :_year(d._year) , _month(d._month) , _day(d._day) { cout << "date(&d)" << this << endl; } private: int _year; int _month; int _day; };
(1)对象实例化
Date t(1996,11,7); Date t1(t); // 调用拷贝构造函数 Date t2 = t; // 调用拷贝构造函数 此处先不考虑赋值操作符重载
(2)传值方式作为函数的参数
void Test(const Date d) //传值方式作为函数的参数 调用拷贝构造函数 { return; }
(3)传值方式作为返回值
Date test() { Date date; // 调用构造函数 return date;// 值传递作为函数返回值 调用拷贝构造函数 //return Date(); // 返回无名对象不掉用拷贝构造函数 只调用构造函数 }
Date& FunTest(Date& d)函数调用顺序
[b]Date FunTest(Date d)函数调用顺序
[/b]
[b]
[/b]
[b]Date FunTest(Date d)函数 返回值是无名对象调用顺序
[/b]
[b]
[/b]
私有的拷贝构造函数:防止一个对象不被通过传值方式传递。
<pre name="code" class="cpp">class A { … private: A(const A &a); // 私有的拷贝构造函数 }; A fun(A a){} A a; A b(a); // 错误,调用私有的拷贝构造函数 b = fun(a); // 错误 ,同上
三 析构函数
析构函数:与构造函数的功能相反,在对象销毁时,由编译器自动调用,完成类的一些资源清理和汕尾工作。
注意:析构函数的目的是在系统回收对象 内存之前执行结束清理工作,以便内存可被重新用于保存新对象。
class CArray { public: CArray(size_t capacity) //构造函数 :_capacity(capacity) { _pData = (int *)malloc(capacity * sizeof(int)); _size = 0; } ~CArray() //析构函数 { if (NULL != _pData) { free(_pData); _pData = NULL; } _size = 0; _capacity = 0; } private: int *_pData; size_t _size; size_t _capacity; };
2 特性
a 析构函数没有参数没有返回值,函数名是类名前加上`.
b 一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。
c析构函数并不是删除对象,只是做一些清理工作。
d 调用次序与构造函数相反,最先构造的对象最后被析构。
四 赋值运算符重载
c++中,对于任何一个类,如果没有用户自定义的赋值运算符函数,系统会自动的生成一个默认的(默认的完成的数据成员的逐位复制)。特殊情况下:如类中有指针形式就不能直接相互赋值,不然可能造成指针悬挂问题。
注意:(1)赋值运算符不能重载为友元函数,只能重载为一个非静态成员函数。
(2)赋值运算符重载函数不能被继承。
Date& Date::operator=(const Date& d) // 赋值运算符重载 { cout << "operator= 赋值运算符重载 " << this << endl; if (this != &d) // 判断是否自己对自己赋值 { _year = d._year; _month = d._month; _day = d._day; } return *this; }
注意 1 在赋值函数为:Date operator=(const Date& d)的情况下
void funTestOperator() { Date d1(2016, 10, 16);// d1 调用构造函数 Date d2(2016, 10, 17);// d2 调用构造函数 Date d3(2016, 10, 18); // d3调用构造函数 d1 = d2 = d3; // 相当于d1.operator=(d2.operator=(d3)) // d2.operator=(d3) 调用一次赋值运算符函数,返回值1调用拷贝构造函数 // d1.operator=(返回值1) 调用第二次赋值运算符函数,返回值2调用拷贝构造函数 // 返回值2 调用析构函数 返回值d1 调用析构函数 } // 函数结束调用d3 d2 d1 的析构函数
2 在赋值函数为:Date& operator=(const Date&d)的情况下
void funTestOperator() { Date d1(2016, 10, 16);// d1调用构造函数 Date d2(2016, 10, 17);// d2调用构造函数 Date d3(2016, 10, 18);// d3调用构造函数 d1 = d2 = d3; // 相当于d1.operator=(d2.operator=(d3)) // 调用两次赋值操作符函数 }
不同的是没有临时对象的产生,因为operator=返回的是对当前对象的引用,而引用只是别名,而不是构造新对象的
区别拷贝构造函数和赋值操作符重载函数的调用区别
Date d1,d3; Date d2 = d1; // 拷贝构造函数 d3 = d1; //赋值操作符重载函数
有什么问题,大家可以评论。
相关文章推荐
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- c++类大四个默认函数-构造函数 析构函数 拷贝构造函数 赋值构造函数
- 深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结
- C++类中的4个特殊函数 - 缺省构造函数、拷贝构造函数、拷贝赋值操作符和析构函数
- 总结笔记-c++成员变量、构造函数以及析构函数的执行顺序
- java 构造函数 成员函数初始化顺序 以及多态的构造函数的调用顺序
- C++继承中析构函数 构造函数的调用顺序以及虚析构函数
- C++类中的4个特殊函数 - 缺省构造函数、拷贝构造函数、拷贝赋值操作符和析构函数
- c++类继承,构造函数和析构函数调用顺序
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- 类中的构造函数与析构函数、函数重载以及this指针的总结
- 深入C++中构造函数、拷贝构造函数、赋值操作符、析构函数的调用过程总结
- 构造函数、拷贝构造函数和析构函数的的调用时刻及调用顺序
- C++类的继承中构造函数和析构函数调用顺序例子
- C++类的构造函数和析构函数的调用顺序
- C++类中的4个特殊函数 - 缺省构造函数、拷贝构造函数、拷贝赋值操作符和析构函数
- C++类的继承中构造函数和析构函数调用顺序例子
- 构造函数、拷贝构造函数、赋值函数、析构函数的调用顺序
- C++继承中构造函数、析构函数调用顺序及虚函数的动态绑定