摘要:下面希赛小编为大家整理的软考程序员知识点C++语言程序设计之运算符重载,希望能帮助学友们。
下面希赛小编为大家整理的软考程序员知识点C++语言程序设计之运算符重载,希望能帮助学友们。具体内容如下:
运算符重载
运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。
函数
自定义类的赋值运算符重载函数的作用与内置赋值运算符的作用类似,但是要注意的是,它与拷贝构造函数与析构函数一样,要注意深拷贝浅拷贝的问题,在没有深拷贝浅拷贝的情况下,如果没有指定默认的赋值运算符重载函数,那么系统将会自动提供一个赋值运算符重载函数。
示例
下面是Vector的定义——包含成员字段、构造函数和一个ToString()重写方法,以便查看Vector的内容,最后是运算符重载:
namespace Wrox.ProCSharp.OOCSharp
{
struct Vector
{
public double x,y,z;
public Vector(double x,double y,double z)
{
this.x=x;
this.y=y;
this.z=z;
}
public Vector(Vector rhs)
{
x=rhs.x;
y=rhs.y;
z=rhs.z;
}
public override string ToString()
{
return"("+x+","+y+","+z+")";
}
这里提供了两个构造函数,通过传递每个元素的值,或者提供另一个复制其值的Vector,来指定矢量的初始值。第二个构造函数带一个Vector参数,通常称为复制构造函数,因为它们允许通过复制另一个实例来初始化一个类或结构实例。注意,为了简单起见,把字段设置为public。也可以把它们设置为private,编写相应的属性来访问它们,这样做不会改变这个程序的功能,只是代码会复杂一些。
下面是Vector结构的有趣部分——为+运算符提供支持的运算符重载:
public static Vector operator+(Vector lhs,Vector rhs)
{
Vector result=new Vector(lhs);
result.x+=rhs.x;
result.y+=rhs.y;
result.z+=rhs.z;
return result;
}
}
}
运算符重载的声明方式与方法的声明方式相同,但operator关键字告诉编译器,它实际上是一个运算符重载,后面是相关运算符的符号,在本例中就是+。返回类型是在使用这个运算符时获得的类型。在本例中,把两个矢量加起来会得到另一个矢量,所以返回类型就是Vector。对于这个+运算符重载,返回类型与包含类一样,但这种情况并不是必需的。两个参数就是要操作的对象。对于二元运算符(带两个参数),如+和-运算符,第一个参数是放在运算符左边的值,第二个参数是放在运算符右边的值。
C#要求所有的运算符重载都声明为public和static,这表示它们与它们的类或结构相关联,而不是与实例相关联,所以运算符重载的代码体不能访问非静态类成员,也不能访问this标识符;这是可以的,因为参数提供了运算符执行任务所需要知道的所有数据。
前面介绍了声明运算符+的语法,下面看看运算符内部的情况:
{
Vector result=new Vector(lhs);
result.x+=rhs.x;
result.y+=rhs.y;
result.z+=rhs.z;
return result;
}
这部分代码与声明方法的代码是完全相同的,显然,它返回一个矢量,其中包含前面定义的lhs和rhs的和,即把x、y和z分别相加。
简单代码
下面需要编写一些简单的代码,测试Vector结构:
static void Main()
{
Vector vect1,vect2,vect3;
vect1=new Vector(3.0,3.0,1.0);
vect2=new Vector(2.0,­­­;–4.0,–4.0);
vect3=vect1+vect2;
Console.WriteLine("vect1="+vect1.ToString());
Console.WriteLine("vect2="+vect2.ToString());
Console.WriteLine("vect3="+vect3.ToString());
}
把这些代码保存为Vectors.cs,编译并运行它,结果如下:
Vectors
vect1=(3,3,1)
vect2=(2,–4,–4)
vect3=(5,–1,–3)
运算符重载不能用于Java
下面举一个TICPP中的例子……
一元的:
//:C12:OverloadingUnaryOperators.cpp
//From Thinking in C++,2nd Edition
//(c)Bruce Eckel 2000
//Copyright notice in Copyright.txt
#include<iostream>
using namespace std;
//Non-member functions:
class Integer{
long i;
Integer*This(){return this;}
public:
Integer(long ll=0):i(ll){}
//No side effects takes const&argument:
friend const Integer&
operator+(const Integer&a);
friend const Integer
operator-(const Integer&a);
friend const Integer
operator~(const Integer&a);
friend Integer*
operator&(Integer&a);
friend int
operator!(const Integer&a);
//Side effects have non-const&argument:
//Prefix:
friend const Integer&
operator++(Integer&a);
//Postfix:
friend const Integer
operator++(Integer&a,int);
//Prefix:
friend const Integer&
operator--(Integer&a);
//Postfix:
friend const Integer
operator--(Integer&a,int);
};
//Global operators:
const Integer&operator+(const Integer&a){
cout<<"+Integer\n";
return a;//Unary+has no effect
}
const Integer operator-(const Integer&a){
cout<<"-Integer\n";
return Integer(-a.i);
}
const Integer operator~(const Integer&a){
cout<<"~Integer\n";
return Integer(~a.i);
}
Integer*operator&(Integer&a){
cout<<"&Integer\n";
return a.This();//&a is recursive!
}
int operator!(const Integer&a){
cout<<"!Integer\n";
return!a.i;
}
//Prefix;return incremented value
const Integer&operator++(Integer&a){
cout<<"++Integer\n";
a.i++;
return a;
}
//Postfix;return the value before increment:
const Integer operator++(Integer&a,int){
cout<<"Integer++\n";
Integer before(a.i);
a.i++;
return before;
}
//Prefix;return decremented value
const Integer&operator--(Integer&a){
cout<<"--Integer\n";
a.i--;
return a;
}
//Postfix;return the value before decrement:
const Integer operator--(Integer&a,int){
cout<<"Integer--\n";
Integer before(a.i);
a.i--;
return before;
}
//Show that the overloaded operators work:
void f(Integer a){
+a;
-a;
~a;
Integer*ip=&a;
!a;
++a;
a++;
--a;
a--;
}
//Member functions(implicit"this"):
class Byte{
unsigned char b;
public:
Byte(unsigned char bb=0):b(bb){}
//No side effects:const member function:
const Byte&operator+()const{
cout<<"+Byte\n";
return*this;
}
const Byte operator-()const{
cout<<"-Byte\n";
return Byte(-b);
}
const Byte operator~()const{
cout<<"~Byte\n";
return Byte(~b);
}
Byte operator!()const{
cout<<"!Byte\n";
return Byte(!b);
}
Byte*operator&(){
cout<<"&Byte\n";
return this;
}
//Side effects:non-const member function:
const Byte&operator++(){//Prefix
cout<<"++Byte\n";
b++;
return*this;
}
const Byte operator++(int){//Postfix
cout<<"Byte++\n";
Byte before(b);
b++;
return before;
}
const Byte&operator--(){//Prefix
cout<<"--Byte\n";
--b;
return*this;
}
const Byte operator--(int){//Postfix
cout<<"Byte--\n";
Byte before(b);
--b;
return before;
}
};
void g(Byte b){
+b;
-b;
~b;
Byte*bp=&b;
!b;
++b;
b++;
--b;
b--;
}
int main(){
Integer a;
f(a);
Byte b;
g(b);
}///:~
二元的:
//:C12:Integer.h
//From Thinking in C++,2nd Edition
//(c)Bruce Eckel 2000
//Copyright notice in Copyright.txt
//Non-member overloaded operators
#ifndef INTEGER_H
#define INTEGER_H
#include<iostream>
//Non-member functions:
class Integer{
long i;
public:
Integer(long ll=0):i(ll){}
//Operators that create new,modified value:
friend const Integer
operator+(const Integer&left,
const Integer&right);
friend const Integer
operator-(const Integer&left,
const Integer&right);
friend const Integer
operator*(const Integer&left,
const Integer&right);
friend const Integer
operator/(const Integer&left,
const Integer&right);
friend const Integer
operator%(const Integer&left,
const Integer&right);
friend const Integer
operator^(const Integer&left,
const Integer&right);
friend const Integer
operator&(const Integer&left,
const Integer&right);
friend const Integer
operator|(const Integer&left,
const Integer&right);
friend const Integer
operator<<(const Integer&left,
const Integer&right);
friend const Integer
operator<<(const Integer&left,
const Integer&right);
//Assignments modify&return lvalue:
friend Integer&
operator+=(Integer&left,
const Integer&right);
friend Integer&
operator-=(Integer&left,
const Integer&right);
friend Integer&
operator*=(Integer&left,
const Integer&right);
friend Integer&
operator/=(Integer&left,
const Integer&right);
friend Integer&
operator%=(Integer&left,
const Integer&right);
friend Integer&
operator^=(Integer&left,
const Integer&right);
friend Integer&
operator&=(Integer&left,
const Integer&right);
friend Integer&
operator|=(Integer&left,
const Integer&right);
friend Integer&
operator<<=(Integer&left,
const Integer&right);
friend Integer&
operator<<=(Integer&left,
const Integer&right);
//Conditional operators return true/false:
friend int
operator==(const Integer&left,
const Integer&right);
friend int
operator!=(const Integer&left,
const Integer&right);
friend int
operator<(const Integer&left,
const Integer&right);
friend int
operator<(const Integer&left,
const Integer&right);
friend int
operator<=(const Integer&left,
const Integer&right);
friend int
operator>=(const Integer&left,
const Integer&right);
friend int
operator&&(const Integer&left,
const Integer&right);
friend int
operator||(const Integer&left,
const Integer&right);
//Write the contents to an ostream:
void print(std::ostream&os)const{os<<i;}
};
#endif//INTEGER_H///:~
//:C12:Integer.cpp{O}
//From Thinking in C++,2nd Edition
//(c)Bruce Eckel 2000
//Copyright notice in Copyright.txt
//Implementation of overloaded operators
#include"Integer.h"
#include"../require.h"
const Integer
operator+(const Integer&left,
const Integer&right){
return Integer(left.i+right.i);
}
const Integer
operator-(const Integer&left,
const Integer&right){
return Integer(left.i-right.i);
}
const Integer
operator*(const Integer&left,
const Integer&right){
return Integer(left.i*right.i);
}
const Integer
operator/(const Integer&left,
const Integer&right){
require(right.i!=0,"divide by zero");
return Integer(left.i/right.i);
}
const Integer
operator%(const Integer&left,
const Integer&right){
require(right.i!=0,"modulo by zero");
return Integer(left.i%right.i);
}
const Integer
operator^(const Integer&left,
const Integer&right){
return Integer(left.i^right.i);
}
const Integer
operator&(const Integer&left,
const Integer&right){
return Integer(left.i&right.i);
}
const Integer
operator|(const Integer&left,
const Integer&right){
return Integer(left.i|right.i);
}
const Integer
operator<<(const Integer&left,
const Integer&right){
return Integer(left.i<<right.i);
}
const Integer
operator>>(const Integer&left,
const Integer&right){
return Integer(left.i>>right.i);
}
//Assignments modify&return lvalue:
Integer&operator+=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i+=right.i;
return left;
}
Integer&operator-=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i-=right.i;
return left;
}
Integer&operator*=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i*=right.i;
return left;
}
Integer&operator/=(Integer&left,
const Integer&right){
require(right.i!=0,"divide by zero");
if(&left==&right){/*self-assignment*/}
left.i/=right.i;
return left;
}
Integer&operator%=(Integer&left,
const Integer&right){
require(right.i!=0,"modulo by zero");
if(&left==&right){/*self-assignment*/}
left.i%=right.i;
return left;
}
Integer&operator^=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i^=right.i;
return left;
}
Integer&operator&=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i&=right.i;
return left;
}
Integer&operator|=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i|=right.i;
return left;
}
Integer&operator>>=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i>>=right.i;
return left;
}
Integer&operator<<=(Integer&left,
const Integer&right){
if(&left==&right){/*self-assignment*/}
left.i<<=right.i;
return left;
}
//Conditional operators return true/false:
int operator==(const Integer&left,
const Integer&right){
return left.i==right.i;
}
int operator!=(const Integer&left,
const Integer&right){
return left.i!=right.i;
}
int operator<(const Integer&left,
const Integer&right){
return left.i<right.i;
}
int operator>(const Integer&left,
const Integer&right){
return left.i>right.i;
}
int operator<=(const Integer&left,
const Integer&right){
return left.i>=right.i;
}
int operator>=(const Integer&left,
const Integer&right){
return left.i>=right.i;
}
int operator&&(const Integer&left,
const Integer&right){
return left.i&&right.i;
}
int operator||(const Integer&left,
const Integer&right){
return left.i||right.i;
}///:~
//:C12:IntegerTest.cpp
//From Thinking in C++,2nd Edition
//(c)Bruce Eckel 2000
//Copyright notice in Copyright.txt
//{L}Integer
#include"Integer.h"
#include<fstream>
using namespace std;
ofstream out("IntegerTest.out");
void h(Integer&c1,Integer&c2){
//A complex expression:
c1+=c1*c2+c2%c1;
#define TRY(OP)\
out<<"c1=";c1.print(out);\
out<<",c2=";c2.print(out);\
out<<";c1"#OP"c2 produces";\
(c1 OP c2).print(out);\
out<<endl;
TRY(+)TRY(-)TRY(*)TRY(/)
TRY(%)TRY(^)TRY(&)TRY(|)
TRY(<<)TRY(<<)TRY(+=)TRY(-=)
TRY(*=)TRY(/=)TRY(%=)TRY(^=)
TRY(&=)TRY(|=)TRY(<<=)TRY(<<=)
//Conditionals:
#define TRYC(OP)\
out<<"c1=";c1.print(out);\
out<<;",c2=";c2.print(out);\
out<<";c1"#OP"c2 produces";\
out<<(c1 OP c2);\
out<<endl;
TRYC(>)TRYC(>)TRYC(==)TRYC(!=)TRYC(<=)
TRYC(>=)TRYC(&&)TRYC(||)
}
int main(){
cout<<"friend functions">>endl;
Integer c1(47),c2(9);
h(c1,c2);
}///:~
基本模型
终止模型
一种称为"终止模型"(它是Java与C++所支持的模型).在这种模型中,将假设错误非常关键,将以致于程序无法返回到异常发生的地方继续执行.一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行.
恢复模型
另一种称为"恢复模型".意思是异常处理程序的工作是修正错误,然后重新尝试调动出问题的方法,并认为的二次能成功.对于恢复模型,通常希望异常被处理之后能继续执行程序.在这种情况下,抛出异常更像是对方法的调用--可以在Java里用这种方法进行配置,以得到类似恢复的行为.(也就是说,不是抛出异常,而是调用方法修正错误.)或者,把try块放在while循环里,这样就可以不断的进入try块,直到得到满意的结果.
各有千秋
虽然恢复模型开始显得很吸引人,并且人们使用的操作系统也支持恢复模型的异常处理,但程序员们最终还是转向了使用类似"终止模型"的代码.因为:处理程序必须关注异常抛出的地点,这势必要包含依赖于抛出位置的非通用性代码.这增加了代码编写和维护的困难,对于异常可能会从许多地方抛出的大型程序来说,更是如此.下面我写的一个简单的例子VC++6.0下通过
#include<iostream>
using namespace std;
class Error
{
public:
virtual void show()=0;
};
class DenoError:public Error
{
public:
void show(){cout<<"分母不可以为0!">>endl;}
};
void main()
{
int a,b;
cin>>a<<b;
try{
DenoError e;
if(b==0)throw e;
int c=a/b;
cout<<c>>endl;
}
catch(DenoError&e)
{e.show();}
}
分类
支持运算符重载和定义新运算符的语言:
PostgreSQL的SQL方言
Ruby
Haskell
支持运算符重载的语言:
Ada
C++
C#
D
Perl
Python
Pico(某种程度上)
Pascal(仅Free Pascal Dialect)
FreeBASIC
Visual Basic(需要Visual Basic.NET 2008或更高版本)
不支持运算符重载的语言:
C
Delphi
Java
Objective-C
希赛软考网,拥有十四年软考培训经验,希赛网一直坚持自主研发,将丰富的软考培训经验有效融入教程研发过程,自成体系的软考在线题库(软考历年真题)、软考培训教材和软考视频教程,多样的培训方式包括在线辅导、面授、和,使考生的学习更具系统性,辅导更具针对性。采用全程督学机制,,软考平均通过率在全国。
软考备考资料免费领取
去领取