总结c++类的构造函数 拷贝构造函数 析构函数 赋值运算符重载的特点以及函数调用顺序

news/2024/7/7 14:57:21

对 c++类的构造函数 拷贝构造函数 析构函数 赋值运算符重载 相关知识的总结,并附上例子,希望对大家有帮助,有错误大家可以指出来

 一 构造函数  
 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)函数调用顺序


Date FunTest(Date d)函数调用顺序


Date FunTest(Date d)函数 返回值是无名对象调用顺序


私有的拷贝构造函数:防止一个对象不被通过传值方式传递。

<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;
}

注意 在赋值函数为: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;  //赋值操作符重载函数

  

有什么问题,大家可以评论。



http://www.niftyadmin.cn/n/4136289.html

相关文章

2.1 线性表的逻辑结构与存储结构

在之前的数据结构知识铺垫2&#xff1a;物理结构与逻辑结构一文中, 我们介绍了物理结构与逻辑结构, 物理结构即存储结构. 本篇文章我们着重探讨一下线性表的逻辑结构与存储结构. 1. 线性表的逻辑结构 图1. 线性表的逻辑结构 线性表是具有相同特性的数据元素的有限序列, 每个元…

springMVC初探视图解析器——XmlViewResolver

XmlViewResolver解析器 XmlViewResolver基于XML文件中的视图bean来解析“逻辑视图”。XmlViewResolver默认会从/WEB-INF/views.xml中加载视图bean&#xff0c; 当然你也可以自己设置该xml文件的位置&#xff0c;该解析器有个属性“location”可设置xml位置 当处理器返回“逻辑视…

python装饰器class_python的装饰器

捋了一遍又一遍&#xff0c;终于对装饰器有了一点点的认识 基本的装饰器长这样&#xff1a; defadd_news(func):def new_func(*args, **kwargs):print("这是新添加的内容")return func(*args, **kwargs)return new_func add_news def my_func(): print("----som…

c++继承知识总结

c继承相关知识总结 一 继承关系&#xff1a;public protected private 不矫情 直接贴代码 举例代码主要从&#xff1a; a. 基类成员对其对象的可见性&#xff1a; 只有public成员可以访问 b. 基类成员对派生类的可见性&#xff1a; c. 基类成员对派生类对象的可见性&#xf…

python字符串小数转化整数_Python字符串、整数、和浮点型数相互转换实例

前言序锦 在编程中&#xff0c;经常要用到字符串的相互转换&#xff0c;现在在这里记录一下Python里面的字符串和整数以及浮点型数之间是如何进行相互转换的。 int(str)函数将符合整数的规定的字符串转换成int型的 float(str)函数将符合浮点型的规定的字符串转换成float型的 st…

《编程之法》1.3字符串的全排列,组合,重复排列,八皇后问题

题目描述&#xff1a;输入一个字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;例如输入"abc"&#xff0c;输出"abc","acb","bac","bca","cab","cba" 解法一&#xff1a;递归实现 类似于…

强强学Android_自定义Button

自定义开关 学习笔记如有错误之处请大家帮忙指出纠正__谢谢-------------------------------------------------------------------------------------------------------------------------------------------难点总结 : 一个自定义控件 即实现了触摸事件 又实现了点击事件 ,…

为什么构造函数不可以声明为虚函数,而析构函数可以

构造函数不能声明为虚函数&#xff0c;析构函数可以声明为虚函数&#xff0c;而且有时是必须声明为虚函数。 不建议在构造函数和析构函数里面调用虚函数。 构造函数不能声明为虚函数的原因是: 1 构造一个对象的时候&#xff0c;必须知道对象的实际类型&#xff0c;而虚函数行为…