14.6 重载运算符、拷贝赋值运算符与析构函数

一:重载运算符

、>、>=、<、<=、!=、++、–、+=、-=、+、-、cout >>、cin<<、= 等运算符。

两个对象是否可以进行比较吗?
是可以比较的,我们需要重载 “==” 运算符,重载:写一个成员函数,这个成员函数名为 “operator ==”,这个成员函数体里边,我们就要写一些比较逻辑。

Time.h

class Time
{
public:
	bool operator==(const Time& time);
public:
	int Hour;
	int Minute;
	int Second;
};

Time.cpp

bool Time::operator==(const Time& time)
{
	if (Hour == time.Hour)
	{
		return true;
	}
	return false;
}

int main()
{
	Time tmpTime1;
	Time tmpTime2;

	if (tmpTime1 == tmpTime2)
	{
		cout << "调用成功" << endl;
	}
	cin.get();
	return 0;
}

总结:
重载运算符,本质上是一个函数。整个函数的正式名字:operator 关键字接运算符。既然重载运算符本质上是一个函数,那么会有返回类型和参数列表。有一些运算符,如果我们不自己写运算符的重载,那么系统会自动给我们生成一个。比如赋值运算符的重载。

Time.h

class Time
{
public:
	int Hour = 0;
	int Minute = 0;
	int Second = 0;  //此处若不赋值将会报错:使用了未初始化的局部变量“tmpTime2”。
				     //与C#不同,C#中对于字段系统会默认初始化,局部变量要求用户初始化。(ps:没记错的话)
};

Time.cpp

int main()
{
	Time tmpTime1;
	Time tmpTime2;
	tmpTime1 = tmpTime2;
	cin.get();
	return 0;
}

二:拷贝赋值运算符

time mytime;		      //调用了默认构造函数
time mytime2 = mytime;	  //调用了拷贝构造函数
time mytime5 = {mytime};  //调用了拷贝构造函数

time mytime6;		//调用了默认构造函数
mytime6 = mytime5;  //这个是赋值运算符,既没有调用构造函数,也没有调用拷贝构造函数。系统会调用一个,拷贝赋值运算符。

我们可以自己重载赋值运算符,如果我们自己不重载,编译器也会为我们生成一个(编译器格外喜欢赋值运算符)。编译器生成的赋值运算符重载比较粗糙。一般就是将非 static 成员赋值给赋值运算符左侧的对象的对应成员中去。如果成员是个类对象的话,可能还会调用这个类的拷贝赋值运算符。

为了精确控制 time 类的赋值动作,我们往往会自己来重载赋值运算符。
重载赋值运算符:有返回类型和参数列表,这里的参数就表示运算符的运算对象。比如 mytime5就是运算对象

赋值运算符重载:

Time& operator=(const Time& tmp)  //tmp 就是 mytime5。
{  
	hour = tmp.hour;
	minute = tmp.minute;
	second = tmp.second;

	cout << "调用了赋值运算符重载" << endl;
	return *this;  //把对象自身(mytime6)返回去
}

time mytime6;
mytime6 = mytime5;  //输出:调用了赋值运算符重载
//mytime6就是 this 对象, mytime5就是operator=里边的参数。

三:析构函数:析构函数相反与构造函数。对象在销毁的时候,会自动调用析构函数。

如果我们自己不写自己的析构函数,编译器也会生成一个默认的析构函数。默认析构函数的函数体为空{},表示默认析构函数没干什么有意义的事情。

构造函数里 new,delete。

析构函数是一个类的成员函数,它的名字是由“~接类名”构成,没有返回值,不接受任何参数,不能重载,一个类只有唯一的一个析构函数。

函数重载:系统允许函数名字相同,但是这些函数的参数个数或者参数类型不同,系统允许这些同名函数同时存在。系统可以判断应该调用那个函数。

~time()
{
	std::cout << "调用了析构函数" << std::endl;
}

构造函数的成员初始化:干了两个事,函数体之前和函数体之中。
析构函数的成员销毁:干了两个事,函数体和函数体之后。
成员变量的初始化和销毁时机:先定义的变量先有值。先定义后销毁。

new 对象和 delete 对象。new 对象的时候,系统调用了time类的构造函数

char* p;	
p = new char[100];
delete[] p;

time *pmytime5  = new time ;  //调用不带参数的构造函数
time *pmytime6  = new time(); //调用不带参数的构造函数

//注意:我们 new 出来的对象,必须要自己释放,否则就会造成内存泄漏。
//在程序停止运行之前的某个时刻,一定要用 delete 把对象占中的内存释放掉。

delete pmytime5;
delete pmytime6; 

//什么时候 delete ,系统就会在什么时候去调用类 time 的析构函数。

创建对象带括号和不带括号的区别

time *pmytime5  = new time ;  //调用不带参数的构造函数
time *pmytime6  = new time(); //调用不带参数的构造函数
<1>对于有构造函数的类:
test t1;    //在堆栈中创建对象和引用,调用test()构造函数
test t2();  //只在栈中创建引用,没有堆中的实例,没有实际对象的创建
<2>对于没有构造函数的类:
test t1;    //在堆栈中创建对象和引用,不进行成员初始化
test t2();  //只在栈中创建引用,没有堆中的实例,没有实际对象的创建
<3>对于内置类型: 
int *p=new int;    //不进行初始化。
int *p=new int();  //初始化为0

四:new 和 delete 对析构函数的影响

class shape
{
public:
	shape()
	{
		cout << "ctor" ;
	}
	~shape()
	{
		cout << "Dtor";
	}
};
int main()
{
	shape a;  //ctor,Dtor。
	shape* b = new shape;  //ctor,无Dtor,若后面添加一条语句delete b;,则有ctor,Dtor。
	//delete b;
	return 0;
}

//注释 delete b 的运行结果:ctorctorDtor
//添加 delete b 后运行结果:ctorctorDtorDtor

你可能感兴趣的:(c++学习,c++)