c++学习笔记(9.操作符重载)

本节知识点:

1.c++标准库:
   a.c++标准库并不是c++语言的一部分,c++标准库是由c++语言编写而成的类库和函数的集合。 c++标准库中定义的类和对象都位于std命名空间中,c++标准库的头文件都不带.h后缀,并且c++标准库涵盖了c库的功能,如c库中<name.h>对应c++库中的<cname>
   b.c++标准库预定义了多数常用的数据结构,如:<bitset> <deque> <list> <map> <queue> <set> <stack> <vector>
   c.c++标准库中的cout和cin的使用方式(代码如下):
#include <cstdio>
#include <iostream>

using namespace std;

int main()
{
	int a;
	int b;
	printf("put a :\n");
	cin >> a;
	printf("put b :\n");
	cin >> b;
	cout << "sum is : " << a+b << endl;
	return 0;
} 
2.全局函数的操作符重载:
   a.c++中可以通过operator关键字利用函数扩展操作符,即操作符重载, operator的本质是通过函数重载实现操作符的重载,所以操作符重载遵循函数重载的规则。
   b.c++中类的友元的定义: private声明使得类的成员不能被外界访问,但是通过friend关键字可以以友元的形式开放权限。友元访问成员变量,依然是通过对象来访问,跟成员函数还是有很大区别的,普通成员函数可以直接访问成员变量,不需要对象。
代码示例如下:
#include <iostream>

using namespace std;
class test
{
private:
	int a;
	int b;
public:
	test (int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	int geta()
	{
		return a;
	}
	int getb()
	{
		return b;
	}
	/*注意友元可以是任何形式的函数*/ 
	friend test operator+ (test& a1, test& a2); //友元声明 
};

test operator+ (test& a1, test& a2) //全局操作符重载函数 
{
	test c(0,0);
	c.a = a1.a + a2.a;
	c.b = a1.b + a2.b;
	return c;
}
int main()
{
	test n1(1,2);
	test n2(2,3);
	test n3(0,0);
	cout << "a is : " << n3.geta() <<endl;
	cout << "b is : " << n3.getb() <<endl;
	n3 = n1 + n2;
	cout << "a is : " << n3.geta() <<endl;
	cout << "b is : " << n3.getb() <<endl;
	return 0;
}

 


注意:上代码中的  n1+n2  其实等价于 operator+(n1, n2)
3.类的成员函数的操作符重载:      
   a.用成员函数重载操作符:比全局函数少一个参数,即左操作数,也是这个类的对象。同时不需要使用friend关键字:
代码如下:
#include <iostream>
#include <cstdio> 
using namespace std;
class test
{
private:
	int a;
	int b;
public:
	test(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	test operator+ (test& n2);
	friend test operator+ (test& n1, test& n2);
	friend ostream& operator<<(ostream& out , test& n);
};
ostream& operator<<(ostream& out , test& n)
{
	out << "a is : " << n.a <<endl;
	out << "b is : " << n.b ;
	return out;
}
test test::operator+ (test& n2) //成员函数的操作符重载 
{
	test n3(0,0);
	n3.a = a + n2.a;
	n3.b = b + n2.b;
	return n3;
}
test operator+ (test& n1, test& n2) //全局函数的操作符重载 
{
	test n3(0,0);
	n3.a = n1.a + n2.a + 2;
	n3.b = n1.b + n2.b + 2;
	return n3;
}
int main()
{
	test n1(2,2);
	test n2(3,3);
	test n3(0,0);
	//n3 = n1 + n2;          //此处的n3 = n1 + n2 用不了 因为有二义性不知道是调用成员函数还是全局函数 
	n3 = n1.operator+(n2);   //成员函数的操作符重载 等效于n3 = n1 + n2; 
	n3 = operator+ (n1, n2); //全局函数的操作符重载 等效于n3 = n1 + n2; 
	cout << n3 <<endl;       //这个<<的重载 不是成员函数的操作符重载 等价于 operator<<(cout,n3); 
	operator<<(cout, n3)<<endl;
	cout.operator<< (55);    //这个是<<在ostream类中的重载函数 的调用 
	return 0;
} 
注意:成员函数的操作符重载, op1 符号 op2  等价于 op1.operator 符号 (op2)   所以说op1必须是这个类的对象
           全局函数的操作符重载, op1 符号 op2 等价于 operator符号(op1, op2)   所以说op1和op2可以是任何类型
4.成员函数和全局函数的操作符重载适用情况:
   a. 如果左操作数不是一个类的对象,只能用全局函数的操作符重载
   b. 当无法修改左操作数的类时,使用全局函数进行重载就像前面重载的<<符号一样,因为不能修改ostream这个类,所以就只能使用全局函数的操作符重载
   c. 其实大量的成员函数的操作符重载,都可以被全局函数的操作符重载代替,但是对于=赋值操作符、[ ]数组运算操作符、()函数调用操作符、->指针操作符只能通过成员函数进行重载。(这四个操作符是c++编译器中的特殊规定只能使用成员函数进行操作符重载,不要问为什么,违反了编译会出错)
   d. c++编译器会为每一个类提供一个默认的赋值操作符,默认的赋值操作符只是做简单的值的复制。当类中存在指针成员变量(尤其是指向new出来的内存的指针)时,就需要重载赋值操作符了,否则在析构函数中delete的时候,就会对同一个地址delete两次!!!
代码如下:
#include <iostream>

using namespace std;

class test
{
private:
	int a;
	int b;
public:
	test(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
/*	test(const test& n)
	{
		cout<<"hhhhhhh"<<endl;
	}*/
	test& operator= (test& n2);
	friend ostream& operator<<(ostream& out , test& n);
};
ostream& operator<<(ostream& out , test& n)
{
	out << "a is : " << n.a <<endl;
	out << "b is : " << n.b ;
	return out;
}
test& test::operator= (test& n2)
{
	a = n2.a + 10;
	b = n2.b + 10;
	return *this;
}
/********************************************************************** 
这里面有一个有意思的东西,就是编译器提供的类的拷贝构造函数中,
有一个类对类赋值的过程  test a = b 是调用拷贝构造函数 

编译器同时对类也提供了一个=赋值运算符的重载成员函数,负责简单
的类之间的赋值,如test a; a = b;这个过程就调用了这个重载的函数

但是他俩都有一个性质,就是如果用户定义了这个函数,编译器提供的
函数就失效了 
**********************************************************************/ 
int main()
{
	test a(2,2);
	test b = a; //调用拷贝构造函数中的赋值过程 
	cout << b;
	
//	test b = test(0,0);
//	b = a;      //调用编译器提供的 =赋值运算符的重载函数 
	test c = test(9,9);
	b = c;
	cout << b;
	return 0;
} 


注意:第一,c++编译器会为类提供一个拷贝构造函数,提供一个赋值操作符重载函数。两个默认函数的功能相同,都是对类的成员变量进行简单的复制。
            第二,但是两个函数之间是相互独立的,有各自的应用场景,如在test b = a; 类定义初始化的时候,此时调用的是类的拷贝构造函数。还有就是在函数参数为类的时候void fun(test a),在函数调用进行参数传递的时候,调用拷贝构造函数,实现实虚参之间的传递。如在b = a 两个类直接赋值的时候,调用的是默认赋值操作符重载函数。
            第三,就是这两个默认提供的函数,一旦用户自己定义了,原来c++编译器提供的默认函数就会失效。
5.++操作符的重载:
   a. c++中通过一个占位参数来区分前置运算和后置运算,且++运算符的重载即可以是全局函数也可以是成员函数,代码如下:
#include <iostream>
using namespace std;
class test
{
private:
	int a;
	int b;
public:
	test(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	friend ostream& operator<<(ostream& out , test& n);
	friend test operator++ (test& a, int);
	friend test& operator++ (test& a);
};
ostream& operator<<(ostream& out , test& n)
{
	out << "a is : " << n.a <<endl;
	out << "b is : " << n.b ;
	return out;
}
test operator++ (test& a, int) //a++ 后置运算 
{
	test ret = a;
	a.a++;
	a.b++;
	return ret;
}
test& operator++ (test& a)  //++a 前置运算 
{
	++a.a;
	++a.b;
	return a;	
}
int main()
{
	test a(0,0);
	test b(9,9);
	test c(8,8);
	b = a++;
	
	cout << b << endl;
	cout << a << endl;
	
	cout << "~~~~~" << endl;
	
	c = ++a;
	cout << c << endl;
	cout << a << endl;
	return 0;
} 


注意: operator++ (test& a, int) 为a++ 后置运算,operator++(test& a) 为++a 前置运算
6.&&和||操作符的重载:
   a. 特别注意不要对&&和||操作符进行重载,因为正常的&&和||内置实现了短路规则,但是操作符重载是靠函数重载来完成的,操作数作为函数参数传递,c++中的函数参数都会被求值,无法实现短路规则。
代码如下:
#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
    int i;
public:
    Test(int i)
    {
        this->i = i;
    }
    
    Test operator+ (const Test& obj)
    {
        Test ret(0);
        
        cout<<"Test operator+ (const Test& obj)"<<endl;
        
        ret.i = i + obj.i;
        
        return ret;
    }
    
    bool operator&& (const Test& obj)
    {
        cout<<"bool operator&& (const Test& obj)"<<endl;
        
        return i && obj.i;
    }
};

int main(int argc, char *argv[])
{
    int a1 = 0;
    int a2 = 1;
    
    if( a1 && (a1 + a2) )
    {
        cout<<"Hello"<<endl;
    }
    
    Test t1 = 0;
    Test t2 = 1;
    
    if( t1 && (t1 + t2) ) // 正常来说如果 t1为0  t1+t2是不应该被执行的  
    {
        cout<<"World"<<endl;
    }
    
    return 0;
}


注意:正常来说 上面的 t1+t2 是应该被短路的,不应该被执行的,但是由于t1+t2实质上是函数的参数,所以被执行了,违背了短路规则!!!
7.本节总结(几个常出面试题):
   a. =赋值操作符 、[]数组操作符 、()函数调用操作符 、->指针操作符,这个四个操作符只能通过成员函数进行重载
   b. ++操作符通过一个int参数进行前置与后置的重载
   c. c++中不要重载&&和||操作符


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值