钻进魔术师的帐篷看对象的前世今生-------------类的6个默认成员函数

介绍类的6个成员函数之前,我们先来看一下this指针

this指针

this 指针是成员函数里面的一个隐藏指针,指向了调用该函数的对象本身。

this指针特性:

(1)this指针的类型为:类类型* const

(2)this指针并不是对象本身的一部分,不影响sizeof结果

(3)this指针的作用域在类“非静态成员函数”内部

(4)this指针是”非静态类成员函数”的第一个默认隐含参数,编译器自动维护传递,类编写者不能显式传递 

(5)只有在类的非静态成员函数中才可以使用this指针,其它任何函数都不可以

(6)this指针不能在初始化列表中使用

(7)当通过this指针访问数据成员时,this指针不能为空

class Test
{
public:
	void FunTest()
	{
		cout << "FunTest():" << this << endl;
		//若不进行注释程序会编译错误,this指针为空,不能使用this指针来访问数据成员
		/*cout << this->_a << endl;*/
	}
private:
	int _a;
};

int main()
{
	Test* pt = NULL;
	pt->FunTest();
	return 0;
}

this指针是使用__thiscall调用约定的

(1)__thiscall只能够用在类的成员函数

(2) 参数从右向左压栈 

(3)如果参数个数确定,this指针通过ecx传递给被调用者;如果参数不确定(_cdecl),this指针在所有参数被压栈后压入堆栈 

(4)对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈

类的6个默认的成员函数


构造函数:

(1)概念:构造函数是一个特殊的成员函数,名字和类名相同无返回值类型,创建类对象时由编译器自动调用在对象的生命周期内只调用一次,保证每个数据成员都有一个合适的初始值

class Date
{
public:
	//初始化列表
	Date(int year,int month,int day)
		:_year(year),_month(month),_day(day)
	{
		cout << "Date(int):" << this << endl;
	}
private:
		int _year;
		int _month;
		int _day;
};

int main()
{
	Date d(2018, 6, 14);
	return 0;
}

(2)特性:1)函数名与类名相同 ,没有返回值 2) 新对象被创建时,由编译器自动调用,且在对象的声明周期内仅调用 一次 3)构造函数可以重载,实参决定了调用哪个构造函数 4)无参构造函数和带有缺省值的构造函数都认为是缺省的构造函数,并 且缺省的构造函数只能有一个 5)有初始化列表6) 如果没有显式定义时,编译器会合成一个默认的构造函数7) 构造函数不能用const修饰8)构造函数不能为虚函数

编译器在什么时候合成默认构造函数?

1)有一个A类,A类中包含缺省的构造函数

2)有一个B类,包含了A类的对象,并且B类没有显式定义自己的构造函数

在这种情况下系统必须为B类合成默认构造函数,目的就是为了构造B对象中包含的A对象

如下:

class Time
{
public:
	Time(int hour=8,int minute=2,int second=45)
		:_hour(hour),_minute(minute),_second(second)
	{}

private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
private:
		int _year;
		int _month;
		int _day;
		Time _t;
};

int main()
{
	Date d;//会调用系统合成的构造函数
	return 0;
}

(3)对象初始化

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表, 每个”成员变量”后面跟一个放在括号中的初始值或表达式  
注意:

1)每个成员在初始化列表中只能出现一次

因为初始化的时候需要划分空间,所以只能出现一次 

2)初始化列表仅用于初始化类的数据成员,并不指定这些数据成员的初始化顺序,数据成员在类中定义顺序就是在参数列表中的初始化顺序,尽量避免使用成员初始化成员,成员的初始化顺序好和成员的定义 顺序保持一致

3)类中包含以下成员,一定要放在初始化列表位置进行初始化:

引用成员变量     const成员变量     类类型成员(该类有非缺省的构造函数)

类中包含类类型成员一定要放在初始化列表位置进行初始化:即A类中有非缺省的构造函数,B类中有构造函数,数据成员包含A类对象。

(4)构造函数作用

1)构造&初始化对象 

2)类型转换   对于单个参数构造函数,可以将其接受参数转化成类类型对象。用 explicit修饰构造函数,抑制由构造函数定义的隐式转换,explicit 关键字类内部的构建声明上,在类的定义体外部的定义上不再重复,如:

class Date
{
public:
	//构造函数用explicit修饰可以避免类型转换问题
	 Date(int year)
		:_year(year)
	{
		cout << "Date(int)" << this << endl;
	}
private:
	int _year;
	int _month;
	int	_day;
};

int main()
{
	Date d1(2018);
	d1 = 2019;//用2019来构造一个临时对象,赋给d1
	return 0;
}

拷贝构造函数

class Date
{
public:
	Date(int year,int month,int day)
		:_year(year),_month(month),_day(day)
	{
		cout << "Date(int):" << this << endl;
	};

	//拷贝构造函数
	Date(const Date& d)
		:_year(d._year)
		,_month(d._month)
		,_day(d._day)
	{
		cout << "Date(const Date&):" << this << endl;
	};
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2018, 6, 14);
	Date d2(d1);
	return 0;
}

(1)概念

只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这 样的构造函数称为拷贝构造函数。拷贝构造函数是特殊的构造函数,创建 对象时使用已存在的同类对象来进行初始化,由编译器自动调用

(2)特征

1)是构造函数的重载,构造函数的性质拷贝构造函数均满足 

2)参数必须使用类类型对象引用传递(为什么?) 

若用值传递传参时,就会调用拷贝构造函数来构造临时变量,形成递归

3)如果没有显式定义,系统会自动合成一个默认的拷贝构造函数。默认 的拷贝构造函数会依次拷贝类的数据成员完成初始化

析构函数

(1)概念

析构函数:与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成类 的一些资源清理和汕尾工作

(2)特性

1)析构函数在类名(即构造函数名)加上字符~ 

2)析构函数无参数无返回值

3) 一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数 

4)对象生命周期结束时,C++编译系统系统自动调用析构函数 

注意析构函数体内并不是删除对象,而是做一些清理工作

赋值操作符重载

操作符重载也是一个函数,具有返回值和形参表,它的形参数目与操作符的操作数数目相同,使用运算符重载可以提高代码的可读性

不可以重载的运算符:.(成员选择符)     .*(成员对象选择符)     ::(域解析操作符)    ?:(条件操作符)

如下日期类的赋值操作符重载:

Date& operator=(const Date& d)
	{
		//排除自己给自己赋值,如果两个地址不一样才进行赋值
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

取地址操作符重载和const修饰的取地址操作符重载:

class Test {
public:
	Test* operator&()
	{
		return this;
	}
	const Test* operator&()const
	{
		return this;
	}
};

综合应用

class Test
{
public:
	//构造函数
	Test()
	{
		cout << "Test()" << this << endl;
	}
	//拷贝构造函数
	Test(const Test& t)
	{
		cout << "Test(const Test&):" << this << endl;
	}
	//赋值操作符重载
	Test& operator = (const Test& t)
	{
		cout << this << "=" << &t << endl;
		if (&t != this)
		{
			;//进行赋值操作
		}
		return *this;
	}
	//析构函数
	~Test()
	{
		cout << "~Test():" << this << endl;
	}
};

Test FunTest(Test t)
{
	Test tt1;
	Test temp(t);
	tt1 = temp;
	return tt1;
}

void TestFunc()
{
	Test t1;
	Test t2;
	t2 = FunTest(t1);
}
int main()
{
	TestFunc();
	return 0;
}

此程序的调用过程为:


猜你喜欢

转载自blog.csdn.net/zimituanzi_/article/details/80695378