C++运算符重载详解(附带实例)
运算符实际上是一个函数,运算符重载本质上就是函数重载。函数重载可以让一个函数根据传入的参数执行不同的操作,运算符重载也一样。当遇到模糊运算时,编译程序会自动寻找与传入参数相匹配的运算符函数。
实际上,C++ 中已经对很多运算符进行了重载。例如,“+”可对不同类型的数据(如 int、float 等)进行加法操作;“<<”既是位移运算符,又可以配合 cout 向控制台输出数据。
C++ 中,数据类型分为基本数据类型和构造数据类型。其中,基本数据类型可以直接完成算术运算。例如,下面的代码实现了两个整型变量相加,输出结果为 30:
类属于用户构造的数据类型,类的两个对象能否通过“+”运算符直接进行求和呢?来看一下示例:
要实现两个类对象的相加有两种方法:一种是通过成员函数,另一种是重载“+”运算符。先来看下如何通过成员函数实现两个对象相加。代码如下:
被重载的运算符只能是 C++ 中已有的运算符,具体如下:
重载运算符时不能改变运算符操作数的个数、原有的优先级、结合性和语法结构,即单目运算符只能重载为单目运算符,双目运算符只能重载为双目运算符。另外,重载运算符的含义必须清晰,不能有二义性。
【实例】通过重载“+”运算符,实现两个 CBook 类对象的求和。具体代码如下:
例如:
对于两个整型变量相加,用户可以调换两个加数的顺序,因为加法符合交换律。但是,对于通过重载运算符实现的两个不同类型的对象相加则不能。因此,下面的语句是非法的:
“++”和“--”运算符涉及前置运算和后置运算,重载这类运算符时该如何进行区分呢?默认情况下,如果重载运算符没有参数,则表示是前置运算。例如:
如果重载运算符使用整数作参数,则表示是后置运算。注意,此时的参数值只是一个标识(标识后置运算),可以忽略。
默认情况下,将一个整数赋值给一个对象是非法的,但通过重载“=”运算符可以将其变为合法。例如:
C++ 程序中,借助复制构造函数可以将一个对象复制成另一个对象。通过重载赋值运算符,也可以将一个整型数复制给一个对象。例如:
还可以通过重载构造函数将一个整数赋值给一个对象。例如:
实际上,C++ 中已经对很多运算符进行了重载。例如,“+”可对不同类型的数据(如 int、float 等)进行加法操作;“<<”既是位移运算符,又可以配合 cout 向控制台输出数据。
C++ 中,数据类型分为基本数据类型和构造数据类型。其中,基本数据类型可以直接完成算术运算。例如,下面的代码实现了两个整型变量相加,输出结果为 30:
int a = 10, b = 20; cout << a + b << endl; // 两个整型变量相加
类属于用户构造的数据类型,类的两个对象能否通过“+”运算符直接进行求和呢?来看一下示例:
#include <iostream> using namespace std; class CBook // 定义CBook类 { public: CBook(int iPage) // 定义构造函数CBook(),初始化图书页码 { m_iPage = iPage; } void display() // 定义成员函数display(),显示图书页码 { cout << m_iPage << endl; } protected: int m_iPage; }; int main() { CBook bk1(10); // 实例化CBook类对象bk1,页码为10 CBook bk2(20); // 实例化CBook类对象bk2,页码为20 CBook tmp(0); // 实例化CBook类对象tmp tmp = bk1 + bk2; // 编译报错,两个对象不能直接相加 tmp.display(); }上述代码中,编译到“tmp=bk1+bk2;”时会报错,因为编译器不知道如何进行两个对象进行相加。
要实现两个类对象的相加有两种方法:一种是通过成员函数,另一种是重载“+”运算符。先来看下如何通过成员函数实现两个对象相加。代码如下:
#include <iostream> using namespace std; class CBook // 定义CBook类 { public: CBook(int iPage) // 定义构造函数CBook(),初始化图书页码 { m_iPage = iPage; } int add(CBook a) // 定义成员函数add(),通过引用成员变量进行相加 { return m_iPage + a.m_iPage; } protected: int m_iPage; }; int main() { CBook bk1(10); // 实例化CBook类对象bk1,页码为10 CBook bk2(20); // 实例化CBook类对象bk2,页码为20 cout << bk1.add(bk2) << endl; // 调用成员函数add(),实现图书页码相加 }程序虽然可以输出正确结果 30,但使用成员函数进行求和形式单一,代码不易复用。如果要实现多个对象的累加,其代码的可读性会大大降低。通过重载运算符就可以解决这些问题。
C++重载运算符的形式与规则
重载运算符的声明形式如下:operator类型名();operator 是需要重载的运算符,整个语句没有返回类型,因为类型名代表了它的返回类型。重载运算符将对象转换成类型名规定的类型,转换时的形式就像强制转换一样,如果没有重载运算符定义,直接用强制转换编译器将无法通过编译。
被重载的运算符只能是 C++ 中已有的运算符,具体如下:
- 算术运算符:+、-、*、/、%、++、--;
- 位操作运算符:&、|、~、^、>>、<<;
- 逻辑运算符:!、&&、||;
- 比较运算符:<、>、>=、<=、==、!=;
- 赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=;
- 其他运算符:[]、()、->、逗号、new、delete、new[]、delete[]、->*。
重载运算符时不能改变运算符操作数的个数、原有的优先级、结合性和语法结构,即单目运算符只能重载为单目运算符,双目运算符只能重载为双目运算符。另外,重载运算符的含义必须清晰,不能有二义性。
注意,并非所有 C++ 运算符都可以重载,不允许重载的运算符有“.”、“.*”、“::”、“?”和“:”。
【实例】通过重载“+”运算符,实现两个 CBook 类对象的求和。具体代码如下:
#include <iostream> using namespace std; class CBook // 定义CBook类 { public: CBook(int iPage) // 定义构造函数,初始化图书页码 { m_iPage = iPage; } CBook operator+(CBook b) // 重载“+”运算符 { return CBook(m_iPage + b.m_iPage); } void display() // 定义display()函数,显示图书页码 { cout << m_iPage << endl; } protected: int m_iPage; }; int main() { CBook bk1(10); // 实例化CBook类对象bk1,页码为10 CBook bk2(20); // 实例化CBook类对象bk2,页码为20 CBook tmp(0); // 实例化CBook类对象tmp tmp = bk1 + bk2; // 重载“+”后,bk1和bk2对象可以直接相加 tmp.display(); // 调用CBook类的display()函数 }程序运行结果为:
30
代码中,CBook 类重载了求和运算符“+”后,由它声明的两个对象 bk1 和 bk2 可以像两个整型变量一样直接相加。C++重载运算符的运算
通过重载运算符,可以实现对象之间的运算,还可以实现对象和普通类型数据之间的运算。例如:
#include <iostream> using namespace std; class CBook // 定义CBook类 { public: int m_Pages; void OutputPages() // 定义OutputPages(),输出图书页码 { cout << m_Pages << endl; } CBook() // 定义构造函数,初始化图书页码 { m_Pages = 0; } CBook operator+(const int page) // 重载“+”运算符 { CBook bk; bk.m_Pages = m_Pages + page; return bk; } }; int main() { CBook vbBook, vfBook; // 定义两个CBook类对象 vfBook = vbBook + 10; // 使用重载后的“+”,vbBook对象和10可以直接相加 vfBook.OutputPages(); // 输出增加10页后的页码 }通过修改运算符的参数为整数类型,可以实现 CBook 对象与整数相加。
对于两个整型变量相加,用户可以调换两个加数的顺序,因为加法符合交换律。但是,对于通过重载运算符实现的两个不同类型的对象相加则不能。因此,下面的语句是非法的:
vfBook = 10 + vbBook; // 非法的代码
“++”和“--”运算符涉及前置运算和后置运算,重载这类运算符时该如何进行区分呢?默认情况下,如果重载运算符没有参数,则表示是前置运算。例如:
void operator++() // 前置运算 { ++m_Pages; }
如果重载运算符使用整数作参数,则表示是后置运算。注意,此时的参数值只是一个标识(标识后置运算),可以忽略。
void operator++(int) // 后置运算 { ++m_Pages; }
默认情况下,将一个整数赋值给一个对象是非法的,但通过重载“=”运算符可以将其变为合法。例如:
void operator=(int page) // 重载赋值运算符 { m_Pages = page; }
C++ 程序中,借助复制构造函数可以将一个对象复制成另一个对象。通过重载赋值运算符,也可以将一个整型数复制给一个对象。例如:
#include <iostream> using namespace std; class CBook // 定义CBook类 { public: int m_Pages; void OutputPages() // 定义成员函数OutputPages() { cout << m_Pages << endl; } CBook(int page) // 构造函数 { m_Pages = page; } void operator=(const int page) // 重载“=”运算符 { m_Pages = page; } }; int main() // 主函数 { CBook mybk(0); // 定义CBook类对象mybk mybk = 100; // 使用重载运算符“=”,为mybk对象赋值 mybk.OutputPages(); // 调用OutputPages()函数 }程序中重载了“=”运算符,给 mybk 对象赋值 100,并通过 OutputPages() 成员函数将该值输出。
还可以通过重载构造函数将一个整数赋值给一个对象。例如:
#include <iostream> using namespace std; class CBook // 定义CBook类 { public: int m_Pages; void OutputPages() // 定义OutputPages()成员函数 { cout << m_Pages << endl; } CBook() // 默认构造函数 { } CBook(int page) // 带参构造函数 { m_Pages = page; } }; int main() // 主函数 { CBook vbBook; // 调用CBook vbBook = 200; vbBook.OutputPages(); }程序中定义了一个重载的构造函数,以一个整数作为函数参数,这可以将一个整数赋值给一个 CBook 类对象。语句“vbBook = 200;”将调用构造函数 CBook(int page) 重新构造一个 CBook 对象,并将其赋值给 vbBook 对象。