C++类与对象(拷贝构造函数以及运算符重载)

目录

1.拷贝构造函数

2.赋值运算符重载函数

本篇讲述以上两种默认函数

拷贝构造函数

我们可以创建一个对象,那么能否再创建一个和这个对象一模一样的的新的对象呢?这就引入了拷贝构造函数
拷贝构造函数与之前讲的构造函数一样,函数名为类名,当用已存在的类类型的对象创建新的对象时,编译器会自动调用拷贝构造函数。

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A(5,1.5)//已经存在的对象
	A1 B(A);//通过A创建一个一模一样的的对象B
}

上面我们没有显式的定义出拷贝构造函数,若要显式定义,如下:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	A1(const A1& a)//拷贝构造函数,需要通过引用传值,否则会一直调用拷贝函数进入死递归
	{
		_a = a._a;
		_b = a._b;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A(5,1.5)//已经存在的对象
	A1 B(A);//通过A创建一个一模一样的的对象B
}

这里的的默认拷贝构造函数,是一种浅拷贝(以后会讲到),资源是拷贝不过去的。
总结:
1.拷贝构造函数是构造函数的一个重载形式。
2.拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。
3.若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝称为浅拷贝,或者值拷贝。
4.如果涉及到资源的拷贝,便需要我们自己显式定义拷贝构造函数,完成资源的拷贝。
5.建议在引用前加上const保证可以使用临时对象进行拷贝

运算符重载函数

如果,我们要判断两个对象是否相等,可以如下:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	bool isequal(const A1& a)//判断是否相等
	{
		return _a == a._a&&_b == a._b;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A;
	A1 B(A);
	cout<<B.isequal(A)<<endl;
}

B.isequal(A)写的话,代码的可读性并不是很高,如果写成A==B的话,那么便一目了然的知道是判断是否相等。因此,这里引入运算符重载函数
运算符重载函数:
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类 型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
例如将上述比较对象是否相等的函数写为运算符重载函数如下:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	bool operator==(const A1& A)
	{
			return _a == A._a&&_b == A._b;
	}
	// bool isequal(const A1& a)
	// {
	// 	return _a == a._a&&_b == a._b;
	// }
private:
	int _a;
	double _b;
};
int main()
{
	A1 A;
	A1 B(A);
	cout<<(A==B)<<endl;
	//cout << A.operator==(B) << endl;等价于上面
	//cout<
}

这里的bool operator==(const A1& a)是有两个参数的,只不过第一个参数是调用者的this指针,即左操作数是this指向的调用函数的对象
当然还有以下这种定义方式:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	bool operator==(const A1& A,const A1& B)
	{
			return B._a == A._a&&B._b == A._b;
	}
	// bool isequal(const A1& a)
	// {
	// 	return _a == a._a&&_b == a._b;
	// }
//private:
	int _a;
	double _b;
};
int main()
{
	A1 A;
	A1 B(A);
	cout<<(A==B)<<endl;
	//cout << A.operator==(B) << endl;等价于上面
	//cout<
}

这是定义的全局的operator== 因此,需要时成员变量是公有的,如果还想要保持封装性的话,就需要用到我们后面学习的友元解决,
再比如我们定义一个求两数的和:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	int operator+(const A1& a)//求两数和
	{
		return _a + a._a;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A;
	A1 B(5,10.2);
	cout<<(A+B)<<endl;
	cout<<A.operator+(B)<<endl;
}

结果如图
C++类与对象(拷贝构造函数以及运算符重载)_第1张图片
总结:
1.不能通过连接其他符号来创建新的操作符:比如operator@
2.重载操作符必须有一个类类型或者枚举类型的操作数
3.用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义
4.作为类成员的重载函数时,其形参看起来比操作数数目少1,成员函数的操作符有一个默认的形参this,限定为第一个形参
5.’*’ 、’::’ 、‘sizeof’ 、’?:’ 、’.’ 注意以上5个运算符不能重载.

赋值运算符重载
之前我们用构造函数或拷贝函数给另对象赋值,这里我们可以通过运算符来赋值,比如:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	//运算符赋值重载函数
	//默认返回的是*this
const A1& operator=(const A1 &A)
	{
		if(this!=&A)
		{
			_a = A._a;
			_b = A._b;
		}
		return *this;
	}
	void display()
	{
		cout<<_a<<" "<<_b<<endl;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A;
	A1 B(5,10.2);
	B.display();
	B = A;//把A赋给B
	B.display();
}

打印结果如图:
C++类与对象(拷贝构造函数以及运算符重载)_第2张图片
注意:
1.=调用:如果对象都存在,调用赋值运算符重载函数, 如果左边对象不存在,调用拷贝构造
2.返回值为引用类型
3.默认返回*this

4.一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝
比如:

class A1
{
public:
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	void display()
	{
		cout<<_a<<" "<<_b<<endl;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A(10,2.5);
	A1 B = A;//编译器为我们默认生成一个赋值运算符重载函数
	B.display();
}

你可能感兴趣的:(C++,c++,类)