c++09_2运算符重载
C++基础系列——运算符重载
C++基础系列——运算符重载1. 运算符重载简介所谓重载,就是赋予新的含义。
函数重载(Function Overloading)可以让⼀个函数名有多种功能,在不同情况下进⾏不同的操作。
同样运算符重载(Operator Overloading)可以让同⼀个运算符可以有不同的功能。
可以对 int、float、string 等不同类型数据进⾏操作<< 既是位移运算符,⼜可以配合 cout 向控制台输出数据也可以⾃定义运算符重载:class Complex{public:Complex();Complex(double real, double imag);Complex operator+(const Complex &a) const;void display() const;private:double m_real;double m_imag;};// ...// 实现运算符重载Complex Complex::operator+(const Complex &A) const{Complex B;B.m_real = this->m_real + A.m_real;B.m_imag = this -> m_imag + A.m_imag;return B;// return Complex(this->m_real + A.m_real, this->m_imag + A.m_imag);}int main(){Complex c1(4.3, 5.8);Complex c2(2.7, 3.7);Complex c3;c3 = c1 + c2; // 运算符重载c3.display();return 0;}运算结果7 + 9.5i运算符重载其实就是定义⼀个函数,在函数体内实现想要的功能,当⽤到该运算符时,编译器会⾃动调⽤这个函数,它本质上是函数重载。
运算符重载(面向对象程序设计C++)
运算符重载运算符重载的本质是函数重载,它也是C++多态的一种体现,为用户提供了一个直观的接口,调用运算符操作自定义数据类型其实就是调用运算符函数。
运算符重载增强了C++的可扩充性,使得C++代码更加直观、易读,且便于对对象进行各种运算操作。
重载的运算符是具有特殊名字的函数:它们的名字由关键字operator 和其后要重载的运算符共同组成。
语法格式 返回类型 operator 运算符(参数列表){函数体; }运算符重载规则:只能重载C++中已有的运算符,不能创建新的运算符。
重载之后的运算符不能改变其优先级和结合性,也不能改变其操作数的个数及语法结构。
避免没有目的地使用重载运算符。
类属关系运算符“.”、成员指针运算符“*”、作用域运算符“::”、sizeof 运算符和三目运算符“?:”不可以重载。
输入输出运算符的重载 IO 标准库使用“>>”和“<<”运算符执行输入输出操作,对于这两个运算符来说,IO 库定义了其基本数据类型的操作,但若要直接对类对象进行输入输出,则需要在类中重载这两个运算符。
输入运算符语法格式istream& operator>>(istream&, 类对象引用);输出运算符语法格式ostream& operator<<(ostream&,const 类对象引用); 关系运算符的设计准则关系运算符都要成对的重载。
“==”运算符应该具有传递性当成对出现运算符重载时,可以把一个运算符的工作委托给另一个运算符。
赋值运算符的重载对于赋值运算符来说,如果不重载,那么类会自动为我们提供一个赋值运算符。
这个默认的赋值运算符跟默认拷贝构造函数一样,就是把一个对象的数据成员的值复制给另一个对象对应的数据成员。
下标运算符的重载返回类型 operator[] (参数列表);重载“[]”运算符可以实现两个目的:(1)“对象[下标]”的形式类似于“数组[下标]”,更加符合习惯。
C语言运算符的重载详解
C语⾔运算符的重载详解⽬录写⼀个Add函数为什么不⽤加号作为函数名运算符的重载上⾯问题解决总结写⼀个Add函数我们先讨论下⾯代码,并复习前⾯的内容class Complex{private:double Real, Image;public:Complex() :Real(0), Image(0) {}Complex(double r, double i) :Real(r), Image(i) {}~Complex() {}//Complex Add(const Complex* const this,const Complex &c)Complex Add(const Complex& x)const{Complex y;y.Real = Real + x.Real;y.Image = Image + x.Image;return y;//return Complex(this->Real + x.Real, this->Image + x.Image);}void Print(){cout << Real << "+" << Image << "i" << endl;}};int main(){Complex c1(12, 23);Complex c2(4.5, 5.6);Complex c3;c3 = c1.Add(c2);c3.Print();return 0;}直接return可以使⽤⽆名函数直接代替将亡值对象,相⽐可以省⼀次对象的构建我们再分析如果我们使⽤引⽤返回Add函数const Complex& Add(const Complex& x)const{Complex y;y.Real = Real + x.Real;y.Image = Image + x.Image;return y;//return Complex(this->Real + x.Real, this->Image + x.Image);}若我们以引⽤返回,将亡值对象会创建在Add函数的栈帧中,然后返回将亡值地址,函数return结束该空间会被释放、若没有引⽤,构建⽆名对象也就是将亡值对象会构建在主函数的空间中,这⾥使⽤将亡值对象值给到c3是没有问题的我们查看对象的构造与析构class Complex{private:double Real, Image;public:Complex() :Real(0), Image(0) {}Complex(double r, double i) :Real(r), Image(i){cout << "Create:" << this << endl;}Complex(const Complex& x):Real(x.Real),Image(x.Image){cout << "Copy Create:" << this << endl;}~Complex(){cout << "~Complex:" << this << endl;}//Complex Add(const Complex* const this,const Complex &c)Complex Add(const Complex& x)const{return Complex(this->Real + x.Real, this->Image + x.Image);}void Print(){cout << Real << "+" << Image << "i" << endl;}};int main(){Complex c1(12, 23);Complex c2(4.5, 5.6);Complex c3;c3 = c1.Add(c2);c3.Print();return 0;}⾸先我们使⽤引⽤返回需要加上const修饰,这是因为我们返回将亡值在临时空间具有常性,所以普通引⽤是不能进⾏返回的,需要使⽤常引⽤返回const Complex& Add(const Complex& x)const{return Complex(this->Real + x.Real, this->Image + x.Image);}我们发现对临时对象的构建后马上就进⾏析构,那么是怎么将数据拿出给到c3的?这个在最后我们进⾏分析为什么不⽤加号作为函数名//Complex operator+(const Complex* const this,const Complex &c)Complex operator+(const Complex &c) const{return Complex(this->Real + x.Real, this->Image + x.Image);}这⾥是不可以的,加号是⼀个操作符,不能使⽤操作放作为有效的函数名称;但是在C++中为了使这些操作符号能够当作函数名,那么我们需要在前⾯加上⼀个关键字operator//Complex operator+(const Complex* const this,const Complex &c)Complex operator+(const Complex &c) const{return Complex(this->Real + x.Real, this->Image + x.Image);}也就是告诉编译器,加号是⼀个有效的函数名,这就叫做运算符的重载;随后我们之间使⽤ c3 = c1 + c2 就是可以的int main(){Complex c1(12, 23);Complex c2(4.5, 5.6);Complex c3;c3 = c1 + c2;//编译器编译会是下⾯的情况//c3 = c1.operator+(c2);//c3 = operator+(&c1,c2); 加上this指针}运算符的重载⼀个对象,编译器会给它有6个缺省函数我们再来看下⾯这个问题//我们写⼀个赋值运算符重载void operator=(const Object& obj){this->value = obj.value;}//返回类型为void,这样不可以就不可以连等//obja = objb = objc;//obja = objb.operator=(objc);//obja = operator=(&objb,objc); 返回的⽆类型,不能给obja赋值且赋值函数不可以定义为const修饰Object& operator=(const Object& obj){this->value = obj.value;return *this;}obja = objb = objc;//改写obja = objb.operator=(objc);obja = operator=(&objb,objc);obja.operator=(operator=(&objb,objc));operator=(&obja,operator=(&objb,objc));通过返回对象,就可以实现连等;并且我们可以通过引⽤返回,因为此对象的⽣存期并不受函数的影响,不会产⽣⼀个临时对象作为⼀个过度防⽌⾃赋值若是我们将obja给obja赋值,也就是⾃赋值obja = objaoperator=(&obja,obja);我们就需要进⾏⼀步判断Object& operator=(const Object& obj){if(this != &obj)//防⽌⾃赋值{this->value = obj.value;}return *this;}上⾯问题解决我们通过这段代码来看,与上⾯问题相同Object& operator=(const Object& obj){if (this != &obj){this->value = obj.value;}return *this;}};Object& fun(const Object& obj){int val = obj.Value() + 10;Object obja(val);return obja;}int main(){Object objx(0);Object objy(0);objy = fun(objx);cout << objy.Value() << endl;return 0;}我们在这⾥希望通过引⽤返回,这⾥return的临时对象会构建在fun函数的栈帧中,并且在函数结束栈帧释放,随后调⽤赋值运算符重载,但是数值依旧是正确的我们跟踪这个被析构对象的地址,⾸先我们定位在fun函数的return obja;,随后进⼊析构函数将我们的obja进⾏析构接着运⾏到回到主函数进⾏赋值,接着进⼊赋值运算符重载,可以看到,这⾥的obj地址与已被析构的obja地址相同可以看到这个值依旧存在,依旧可以打印给出,这是因为vs2019的特殊性质造成的;我们每次运⾏程序会发现每次的对象地址都在变化,逻辑地址会随机改变,被析构对象的栈帧不会被接下来的赋值运算符重载扰乱地址空间,所以即使我们引⽤返回的对象已经死亡依旧可以将数值正确返回但是在vc中,我们得到的值会是随机值,这是因为vc中每次运⾏程序地址都不会改变,当我们从fun函数退出进⼊赋值语句中,就会将原本存储数据的地址扰乱,继⽽变成了随机值尽管我们引⽤返回能够将数据正确打印,但是该对象已经死亡,这是不安全的,所以我们⼀定不要以引⽤返回对象VS2019具有⼀个特点:当我们调⽤函数,若函数中没有定义局部变量或局部对象时,该函数基本不对栈帧进⾏清扫总结到此这篇关于C语⾔运算符的重载详解的⽂章就介绍到这了,更多相关C语⾔运算符重载内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
C++第9章运算符重载
§9-2 重载运算符的基本格式
RMB RMB::operator +(RMB &s) { unsigned int c=jf+s.jf; unsigned int d=yuan+s.yuan; if(c>=100) { c-=100; d++; } RMB result(d,c); return result; } RMB & RMB::operator ++(); { jf++; if(jf>=100) { jf-=100; yuan++; } return *this; } void main() { RMB d1(1,60); RMB d2(2,50); RMB d3(0,0); d3=d1+d2; ++d3; d3.display(); }
§9-1 使用运算符重载的必要性
9.1 使用运算符重载的必要性
运算符重载就是对已有的运算符赋予多重含义, 使同一个运算符作用于不同类型的数据,导致不 同类型的行为。
RMB a(10,23),b(20,45),c;
c=a+b; //c=add(a,b);
运算符重载可以增加可读性,使用户定义数据类
型直接使用运算符进行运算,但不是非有不可。
§9-1 使用运算符重载的必要性
class RMB{ //人民币类 public: RMB(double d){ yuan=d; jf=(d-yuan)*100; } RMB interest(double rate); //计算利息 RMB add(RMB d); //人民币加 void display(){ cout <<(yuan + jf / 100.0) << endl; } RMB operator+(RMB d) { return RMB(yuan+d.yuan+(jf+d.jf)/100.0); } RMB operator*(double rate) { return RMB((yuan+jf/100.0)*rate);} private: unsigned int yuan; //元 unsigned int jf; //角分 };
运算符重载
{
rpart=rp;
ipart=ip;
}
Complex add( const Complex & com )
{
Complex temp ;
temp .rpart= com .rpart+rpart;
temp .ipart= com .ip+ipart;
return temp ;
}
2020/7/2
பைடு நூலகம்};
★单目运算符重载 :
Complex Complex:: operator {
Complex temp;
( 单) 目无参数 双目一个参数
temp.rpart=-rpart;
temp.ipart)=-ipart;
return temp;
}
Complex c=-a+b;
(a.operator-( )).operator+(b)
};
point point::operator+ (point p1)
{ point p; p.x=x+p1.x; p.y=y+p1.y; return p; }
void main()
{ point p1(10,10),p2(20,20); p1=p1+p2 ;
p1.print(); ++p1; p1.print();
}
//(╳)
运算符成员函数——调用成员函数的对象隐式成为表达式的第一个运算数 外部运算符函数——其第一个参数直接对应表达式的第一个运算数;
x1=x2+x3;
operator+(x2, x3);
2020/7/2
6 6
简述运算符重载的规则。
简述运算符重载的规则。
篇一:运算符重载是C/C++语言中一种强大的功能,允许程序员自定义函数的行为,以处理不同类型的数据。
运算符重载允许程序员在函数中重载算术、逻辑和位运算符,从而能够处理数组、结构体和指针等不同类型的数据。
以下是运算符重载的规则:1. 算术运算符重载算术运算符包括加号、减号、乘号和除号。
每个算术运算符都有一组默认的行为,可以通过运算符重载来自定义它们的行为。
例如,重载加号运算符可以使函数接受一个整数参数,并返回一个新的整数。
下面是一个简单的例子,演示了如何重载加号运算符:```c++struct MyStruct {int value;};MyStruct operator+(const MyStruct& other, int value) {return MyStruct(value + other.value);}int main() {MyStruct mystruct1 = { 10 };MyStruct mystruct2 = { 20 };int result = mystruct1 + mystruct2;std::cout << "result = " << result << std::endl;return 0;}```在上面的例子中,我们定义了一个名为`MyStruct`的结构体类型,其中包含一个整数类型。
然后,我们定义了一个重载加号运算符的函数,该函数接受一个整数类型的参数,并返回一个新的`MyStruct`对象。
在`main`函数中,我们定义了两个`MyStruct`对象`mystruct1`和`mystruct2`,并将它们相加,结果存储在`result`变量中。
2. 逻辑运算符重载逻辑运算符包括条件运算符和逻辑非运算符。
每个逻辑运算符都有一组默认的行为,可以通过运算符重载来自定义它们的行为。
轻松学C#之运算符重载
”和“>”,判断三个对象的大小, 输出最大对象。 在该例中,返回数据类型必须是bool,否则会提示错误。错 误信息如下: 无法将类型”bool”隐式转换为”重载关系运算符.Program” 而且,如果重载“<”运算符,那么也必须重载“>”运算符, 否则编译器会报错。错误信息如下: 运算符”重载关系运算符.Program.operator >(重载关系运算 符.Program,重载关系运算符.Program)”要求也要定义匹配的 运算符”<”
Team
operator
+
(Team oper1,Team oper2)
//方法代码暂时省略 }
public static是修饰符。Team表示运算的结果类型。operator是 运算符重载的关键字。oper1和oper2是Team类类型的两个参数。 注意:该参数类型必须是对象或者结构。如果不是,会提示 如下错误信息: 运算符的参数必须是包含类型。
返回数据类型 运算符
public static bool { //return true/false; } public static bool { //return true/false; }
operator
>
(Program op1,Program op2)
operator
<
(Program op1,Program op2)
9.1 什么是运算符重载
运算符重载是根据用户所创建的类来定义运算符的含义。 这样运算符的作用完全由用户决定,同时类和类之间的 运算符含义可以不同。换句话说,通过运算符的重载改 变了运算符运算的规则,可以扩展运算符在类中的作用。 通常情况下,运算符只允许数与数、数与数据和数据与 数据之间的运算。通过运算符的重载,不同类型的对象 都可以进行运算。
运算符重载——精选推荐
运算符重载运算符重载学习运算符重载,让运算符能做⼀些原来做不了的事情,⽅便它的使⽤⼀、运算符重载的概念1、什么是运算符重载1.重载:重新载⼊,就像之前学的函数重载,对⼀个已有的函数赋值⼀个新的定义,因此同⼀个函数名就可以有不同的含义。
2.运算符也是可以重载的,⽐如cout在输出⼀个变量的时候,能接受不同类型的数据并输出,他就是重载了<<运算符,这个就是运算符重载3.所以运算符重载指的是对已有的运算符重新定义新的运算规则,以适应不同的数据类型,当然重载之后之前的运算规则还是有的2、为什么要进⾏运算符重载1.运算符重载之后可以让运算符去适应不同的数据类型,对于基本数据类型,系统给出了运算符的操作规则,对于⾃定义数据类型来说,系统不知道该给出什么规则class student{int id;int age;char name[20];public:student(int id,int age,const char* name){this->id=id;this->age=age;strcpy(this->name,name);}}student stu1(1,23,"张三");student stu2(2,24,"李四");stu1+stu2;//如果是这样相加,那么应该加的是什么呢?编译器是不知道的,所以编译器就提供了运算符重载这个机制,让⽤户⾃定义运算符的运算规则⼆、运算符重载1、运算符重载类中定义1.关键字:operator,通过关键字来定义运算符重载(跟写个函数⼀样)2.定义:函数返回值类型 operator 要加载的运算符(参数列表){函数体;}这⾥把运算符的使⽤,理解为调⽤函数,只是和平时的调⽤函数有⼀点区别#include<iostream>#include<string>using namespace std;class student{int id;int age;string name;public:student(int age){this->age = age;id = 1;name = "sss ";}student(int id, int age, string name){this->id = id;this->age = age;this->name = name;}void showstudent(){cout << id << "\t" << age << "\t" << name << endl;}student operator+(student& p1)//这个函数会返回⼀个新的对象{int x=this->age + p1.age;student p(x);return p;//返回的是⼀个对象,会调⽤拷贝构造}int operator-(int x){return this->id - x;}void operator+(student&p2){cout << this->id + p2.id << endl;}};//1.操作这个运算符之后,返回值类型是什么int main(){student p1(0, 1, "yunfei");int x = p1.operator-(1);cout << x << endl;student stu1(1, 23, "张三");student stu2(2, 24, "李四");//student stu3 = stu1.operator+(stu2);//student stu3 = stu1 + stu2;stu1 + stu2;//stu3.showstudent();system("pause");return 0;}注意:因为我们这个运算符是在类中写的,所以是通过对象调⽤的,那么this指针会占⼀个参数,⽽且是第⼀个参数,也就是说我们重载⼀个运算符,是在类中,⽽这个运算符是个单⽬运算符,那么参数列表就不⽤写东西了,是双⽬运算符,那么就需要传另⼀个参数进来绝⼤部分的运算符重载都可以参照上⾯这个+号重载2、运算符重载的特点1.⼏乎所有的运算符都可以被重载,除了 . :: ()?() ) sizeof()2.运算符重载基本出现在类中和结构体中3.运算符可以理解为函数的⼀个表现3、运算符重载的注意事项1.重载运算符,这个重载的运算符还是满⾜原来的原则,但不能说重载+号,结果做的事-号的事,这样会使运算符的运⽤上增加很⼤的难度2.运算符重载的参数,类中重载调⽤对象会占⼀个参数,就是this会占⼀个参数,参数列表就是⽤来表⽰运算符的操作的3.对于运算符重载的调⽤,可以直接使⽤运算符,也可以通过对象 . 出来调⽤4.考虑返回值,不同的运算符有不同的返回值,要记得满⾜运算符原来的规则4、使⽤友元函数,实现运算符重载1.类在已经实现且部分修改的情况下下,需要进⾏运算符重载,就可以通过友元的⽅式来进⾏重载#include<iostream>#include<string>using namespace std;class person{int id;int age;string name;public:person(int id, int age, string name){this->id = id;this->age = age;this->name = name;}void showperson(){cout << id << "\t" << age << "\t" << name << endl;}friend int operator+(person&p1, person&p2);};//形参使⽤的是类对象的引⽤,在实参传对象的时候不会调⽤拷贝构造int operator+(person&p1, person&p2){return p1.id + p2.id;}//1.操作这个运算符之后,返回值类型是什么int main(){person stu1(1, 23, "张三");person stu2(2, 24, "李四");int x = operator+(stu1, stu2);//显⽰调⽤int y = stu1 + stu2;//隐式调⽤cout << x << endl << y << endl;system("pause");return 0;}容器:#include<iostream>#include<vector>using namespace std;int main(){//int 是v1这个容器存的类型vector<int> v1;for (int i = 0; i < 10; i++){//push_back()是⼀个函数,功能是尾插元素v1.push_back(i + 1);}for (int i = 0; i < 10; i++){cout << v1[i] << "\t";}system("pause");return 0;}左移右移运算符重载:#include<iostream>using namespace std;class person{int id;public:person(int id){this->id = id;}friend ostream& operator<<(ostream& os, person& p1);friend istream & operator>>(istream & in, person & p2);};//左移右移运算符重载,必须在类外重载,通过友元实现ostream& operator<<(ostream& os, person& p1)//左移运算符{os << p1.id << endl;return os;//返回的是⼀个cout,⽽且只能⽤引⽤}istream & operator>>(istream & in, person & p2)//右移运算符{in >> p2.id;return in;}int main(){person p1(10), p2(20);cin >> p1 >> p2;cout << p1 << endl << p2 << endl;system("pause");return 0;}前++,后++运算符重载:#include<iostream>using namespace std;class person{int id;public:person(int id){this->id = id;}person& operator++()//前++{this->id++;return *this;}person& operator++(int)//后++,int是⼀个占位符,⽤来区分前++和后++的{static person temp = *this;//引⽤不能返回局部变量,要⽤静态变量this->id++;return temp;}friend ostream& operator<<(ostream& os, person& p1);friend istream & operator>>(istream & in, person & p2);};//左移右移运算符重载,必须在类外重载,通过友元实现ostream& operator<<(ostream& os, person& p1)//左移运算符{os << p1.id << endl;return os;//返回的是⼀个cout,⽽且只能⽤引⽤}istream & operator>>(istream & in, person & p2)//右移运算符{in >> p2.id;return in;}int main(){person p1(10), p2(20);//cin >> p1 >> p2;//cout << p1 << endl << p2 << endl;cout << p1 ;//10cout << p1++ ;//10cout << p1 ;//11cout << ++p1 ;//12cout << p1 ;//12system("pause");return 0;}等号运算符重载:#include<iostream>using namespace std;class person{char* name;public:person(const char* name){this->name = new char[strlen(name) + 1];strcpy(this->name, name);}person& operator=(person&p1)//⽤不⽤引⽤传参,要看返回的对象会不会消失 {if (this->name != NULL){delete[]this->name;this->name = NULL;}this->name = new char[strlen() + 1];strcpy(this->name, );return *this;}void show(){cout << name << endl;}~person()//如果有申请函数,就要加上析构函数{if (name != NULL){delete[]name;name = NULL;}}};int main(){{person p1("张三"), p2("李四"), p3("王五");p1 = p2 = p3;p1.show();p2.show();p3.show();}//加上⼤括号,让对象死亡,就能调⽤析构函数system("pause");return 0;}智能指针和==号运算符重载:#include<iostream>using namespace std;class person{int id;public:person(int id){this->id = id;}void show(){cout << id << endl;}bool operator==(person& p){return this->id == p.id;}~person(){cout << "person的析构函数" << endl;}};class smartpointer{person* ps;//包含你要new出来的对象的类的指针public:smartpointer(person* p){ps = p;}//重载->person* operator->()//传回来的是地址,不是对象,不⽤引⽤{return ps;}//重载*person& operator*()//返回的是对象,会调⽤拷贝构造,所以⽤返回值⽤引⽤,就不会再调⽤拷贝构造了 {return *ps;//得到⼀个对象,}~smartpointer(){if (ps != NULL){delete ps;ps = NULL;}}};int main(){{smartpointer p(new person(5));p->show();(*p).show();person p1(1), p2(3);cout << (p1 == p2) << endl;}//有三个对象,所以析构函数执⾏了三次system("pause");return 0;}[]运算符重载:#include<iostream>using namespace std;class person{char* name;public:person(const char* name){this->name = new char[strlen(name) + 1];strcpy(this->name, name);}char& operator[](int index){return name[index];}~person(){if (name != NULL){delete[]name;name = NULL;}cout << "这是析构函数" << endl;}};int main(){person p("asdfg");cout << p[3] << endl;system("pause");return 0;}c++引⽤作为函数返回值:1.以引⽤返回函数值,定义函数时需要在函数名前加 &2.⽤引⽤返回⼀个函数值的最⼤好处是,在内存中不产⽣被返回值的副本3.返回值为引⽤的时候,返回的是⼀个地址,隐形指针4.当返回值不是引⽤时,编译器会专门给返回值分配出⼀块内存的引⽤作为返回值,必须遵守以下规则:(1)不能返回局部变量的引⽤。
c++ 仿函数和运算符重载
c++ 仿函数和运算符重载C++ 中的仿函数(functor)和运算符重载(operator overloading)是两个与函数和运算符相关的概念,它们在C++ 编程中非常有用,可以增强代码的可读性和可维护性。
1. 仿函数(Functor)在C++ 中,仿函数是指一个重载了operator()的类的对象。
换句话说,仿函数是一个可以像函数一样被调用的对象。
下面是一个简单的仿函数的例子:cppclass Add {public:int operator()(int a, int b) {return a + b;}};int main() {Add addObj; // 创建仿函数对象int result = addObj(3, 4); // 像调用函数一样调用仿函数对象std::cout << "The result is: " << result << std::endl; // 输出 7return0;}在这个例子中,Add类是一个仿函数类,因为它重载了operator()。
我们可以创建Add类的对象,并像调用函数一样调用这个对象。
2. 运算符重载(Operator Overloading)在C++ 中,运算符重载是一种形式的多态,它允许程序员为自定义的数据类型重新定义运算符的行为。
通过运算符重载,我们可以使自定义的数据类型表现得像内置的数据类型一样。
下面是一个简单的运算符重载的例子:cppclass Complex {public:Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {} // 重载 + 运算符Complex operator+(const Complex& c) {return Complex(real + c.real, imag + c.imag);}void print() {std::cout << real << " + " << imag << "i" << std::endl;}private:double real, imag;};int main() {Complex c1(1.0, 2.0), c2(3.0, 4.0);Complex c3 = c1 + c2; // 使用重载的 + 运算符c3.print(); // 输出 4.0 + 6.0ireturn0;}在这个例子中,Complex类重载了+运算符,以便可以对两个Complex对象执行加法操作。
第9章 C++重载(Overload)
重载(Overload)是C++所提供的新增语法。它总共分为两 种类型:函数的重载与运算符的重载,目的是使程序得到更 直观、更为易读的语法。
9-1 函数的重载 9-2 运算符的重载
10
9-1 函数的重载
在第5章中我们曾经对于函数的使用作了 一番探讨。不过在那时我们对于函数的名称并 没有介绍的很详细,主要是由于它牵涉到重载 的概念。
在此,参数也可以使用传值或传址的方式传入。同样的,使用传值参数时在函数中所做的 变量并不会影响到原本的变量,因为它所使用的只是一个复制而已。如果使用传址参数时,由 于函数内外都是使用同一个地址,因此更改时也会变动到原始数据。不过通常在进行运算符重 载时都不会改变原值,只有在使用单一操作数的运算符重载时才有必要使用传址,关于这点我 们会在之后的章节再作讨论。
后缀
后缀和前缀是相对的概念,前缀是在运算还未进行前就先执行, 而后缀则是等到其执行后才执行,因此其结果往往有很大的差异。
可以发现它在声明时多加了一个参数varl,实际上这个参 数从头到尾都没有被使用到,因此取什么名字都没关系。由于 它的存在,告知了编译器这段程序是在进行递增符号的后缀重 置工作。在函数内部使用了与前缀相似的语法,只不过将前缀 改为后缀而已。
说细的程序代码!200 v来自id showInfo ( int ID , char name[] )
210 {
230 cout << "Enter function 3" << endl ;
240 cout << "Your ID is " << ID << endl ;
250 cout << "Your name is " << name << endl ;
《C运算符重载》PPT课件
h
4
二元运算符重载(2)
函数的返回值 返回引用 返回非常量值 返回常量值 返回值优化
重载+和+=运算符对(- -=, * *=, 等)
h
5
重载赋值p; operator=(const T&);
默认的赋值运算
限制赋值运算
重载赋值运算符
原因:成员有指针,并动态分配内存时。 检查自我赋值:
• 效率
• a=a; 的情况
h
6
一元运算符
全局函数 成员函数 增量/减量运算符(++/--)
前缀:T& operator++ (); 后缀:T operator++(int);
迭代器
h
7
重载运算符的方针
运算符 所有的一元运算符 = () [] -> ->* += -= *= /= ^=&=|=%=>>=<<= 成员 所有其他二元运算符
成员 非成员
建议使用 必须是成员
h
8
运算符重载
h
1
重载运算符
意义(例)
重载条件 自定义的类型 不可重载的运算符 :: . ->* 不可使用新的运算符
运算符重载 一元/二元运算符: 全局函数/成员函数
h
2
二元运算符重载(1)
全局函数格式: 成员函数的格式: 重载后的表达式形式(成员函数)
左结合:a+b+c; (a.operator+(b)).operator+(c)
运算符重载解读
02
在重载运算符时,应明确指定 运算符的参数类型和返回类型 ,避免与其他操作符混淆。
03
在重载运算符时,应尽量使用 有意义的操作符名称,以提高 代码的可读性。
考虑性能和效率
01
02
03
运算符重载时,应考虑 性能和效率,避免对原 有代码造成不必要的性
能损失。
在重载运算符时,应尽 量减少额外的计算和内 存开销,以提高代码的
一元运算符重载
一元运算符重载是指对一元运算符进行重载,使其能够应用于一个操作数。例如,在C中,我们可以 重载一元减号运算符(-)来返回一个数的相反数。
常见的一元运算符有:+、-、~、!等。
二元运算符重载
二元运算符重载是指对二元运算符进行重载,使其能够应用于两个操作数。例如,在C中,我们可以重载加号运算符(+)来定 义两个自定义类型的相加行为。
01
提高代码可读性
运算符重载可以使代码更易读, 因为运算符的使用可以使代码更 简洁、更直观。
02
03
方便函数调用
运算符重载可以使得函数调用更 加方便,因为运算符的使用可以 减少函数调用的开销。
04
缺点分析
易造成混淆
运算符重载可能会使得代码难以理解,因为 运算符的行为可能会被改变,导致读者难以
理解代码的含义。
常见的二元运算符有:+、-、*、/、%等。
三元运算符重载
三元运算符重载是指对三元运算符进行重载,使其能够应用于三个操作数。例如,在C中,我们可以重载条件运 算符(?)来定义一个自定义类型的条件判断行为。
常见的三元运算符有:?:。
03
运算符重载的常见场景
类与类之间的运算
01
两个类对象之间的加法运算,可以表示它们之间的某种关联或 合并。
C程序设计运算符重载资料
•
{
目的对象与源对象不是同一个对象
•
……
复制被被赋值对象
•
}
•
*;
返回目的对象
•}
*重载赋值运算符“=”
• 如用户没有为一个类重载赋值运算符,编译程序将生成一个默认赋值运算符函数。赋值运算 把源对象的数据成员逐个地复制到目的对象的相应数据成员
0;
返回值0, 返回操作系统
}
程序运行时屏幕输出如下: 6 -6 请按任意键继续. . .
用类的友元函数重载双目运算符
• 将双目运算符重载为类的友元函数时,友元函数形参表中包含有两个参数,这两个参数分别 作为运算符的左、右操作数。
例4.6 双目运算符重载为类的友元函数示例。
<>
编译预处理命令
;
使用命名空间
例4.8 双目运算符重载为普通函数示例。 声明整型类
{
:
数据成员
;
数据值
:
公有函数
( n = 0): (n){ }
构造函数
( n) { = n; }
设置数据值
() { ; } 返回数据值
};
( , ) 重载运算符"+"
{ (() + ()); }
()
主函数()
{
i(6), j(9), k;
定义整型对象
例4.5 单目运算符重载为类的友元函数示例。
<>
编译预处理命令
;
使用命名空间
声明整型类
{
: 数据成员
在 6.0下会出现的编译时错语,是 6.0的一个,在
<> ;;
编译预处理:
:
改为:
运算符重载详解
运算符重载详解1.运算符重载定义:C++中预定义的运算符的操作对象只能是基本数据类型。
但实际上,对于许多⽤户⾃定义类型(例如类),也需要类似的运算操作。
这时就必须在C++中重新定义这些运算符,赋予已有运算符新的功能,使它能够⽤于特定类型执⾏特定的操作。
运算符重载的实质是函数重载,它提供了C++的可扩展性,也是C++最吸引⼈的特性之⼀。
运算符重载是通过创建运算符函数实现的,运算符函数定义了重载的运算符将要进⾏的操作。
运算符函数的定义与其他函数的定义类似,惟⼀的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的。
运算符函数定义的⼀般格式如下:<返回类型说明符> operator <运算符符号>(<参数表>){<函数体>} 2.运算符重载时要遵循以下规则:(1) 除了类属关系运算符"."、成员指针运算符".*"、作⽤域运算符"::"、sizeof运算符和三⽬运算符"?:"以外,C++中的所有运算符都可以重载。
(2) 重载运算符限制在C++语⾔中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。
(3) 运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。
(4) 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
(5) 运算符重载不能改变该运算符⽤于内部类型对象的含义。
它只能和⽤户⾃定义类型的对象⼀起使⽤,或者⽤于⽤户⾃定义类型的对象和内部类型的对象混合使⽤时。
(6) 运算符重载是针对新类型数据的实际需要对原有运算符进⾏的适当的改造,重载的功能应当与原有功能相类似,避免没有⽬的地使⽤重载运算符。
(7)重载运算符的函数不能有默认的参数,否则就改变了运算符的参数个数,与前⾯第3点相⽭盾了;(8)重载的运算符只能是⽤户⾃定义类型,否则就不是重载⽽是改变了现有的C++标准数据类型的运算符的规则了,会引会天下⼤乱的;(9)⽤户⾃定义类的运算符⼀般都必须重载后⽅可使⽤,但两个例外,运算符“=”和“&”不必⽤户重载;(10)运算符重载可以通过成员函数的形式,也可是通过友元函数,⾮成员⾮友元的普通函数。
介绍C#中的运算符重载.
介绍C#中的运算符重载.介绍 C# 中的运算符重载周融,2007 年 5 ⽉(C) 2001-2007 保留所有权利。
重载是⾯向对象中的⼀个重要概念,它是对象多态性的⼀种不完全体现,⼈们通常所说的重载,往往指的是函数的重载。
本⽂向读者介绍⼀种新的重载模型——运算符重载。
在本⽂中的内容:1、为什么需要运算符重载2、C# 运算符重载决策⽰例3、C# 运算符重载⼀览表4、结论为什么需要运算符重载函数的重载为⼀个对象上的相同⾏为提供不同的参数⽅式,这样,开发⼈员便可以使⽤这些不同的参数实现类似的功能。
⼀组函数重载决策⼀般实现的功能是相同的,例如对 Object 对象上的 ToString() ⽅法就有⼏个重载版本,虽然它们接受的参数不同,但却都表达同⼀个⾏为的最终结果。
参数的不同导致函数重载版本的签名不同,这样编译器很容易知道需要调⽤那⼀个重载版本。
这种技术给开发⼈员带来了⽅便。
现在我们试图对重载的定义进⾏推⼴。
先让我们看看最简单的例⼦,我们通常需要像这样声明并初始化⼀个值类型的变量:int digit = 5;string sayHello = "Hello, World";这⾥的“=”运算符,就是将右边的值传递给左边变量的赋值运算符。
这⾥,5 的类型为 int,“Hello, World”的类型为 string,这与左边被赋值的变量类型完全⼀致。
但对于上述的解释,我们还可以这样认为:5 的类型为 uint 或 byte,"Hello, World"的类型为 char[],那么如此⼀来,赋值运算左边和右边的类型就不在等同,那么编译器如何处理呢?有⼈会说,这就是“隐式类型转换”,这个答案确实很好,但隐式类型转换的规则已经被编译器确定,如果赋值运算的两端不遵循隐式类型转换规则,则需要显式类型转换,例如:char c = '2';string s = (string)c;int i = (int)c;这些显式类型转换并不适⽤于任何场合,也许⼈们希望在其⾃定义的类中也能⽤赋值、加减乘除等语法操作它们。
二级C++考点归纳:运算符重载
二级C++考点归纳:运算符重载二级C++考点归纳:运算符重载8.1 运算符函数据与运算符重载运算符重载是计算机语言固有多态性的体现,是构成计算机语言的基础之一。
C++把重载的运算符视为特殊的函数,称为运算符函数。
运算符重载就是函数重载的一种特殊情况。
像对待一般重载函数一样,编译系统能够依据使用运算符的不同环境,即参数(操作数)的数量或类型的差异,区分同一运算符的不同含义。
运算符重载是针对C++中原有运算符进行的,不可能通过重载创造出新的运算符。
除了。
、。
*、-*、::、?:这五个运算符外,其他运算符都可以重载。
由于很多符号是一元运算符和二元运算符公用的,为了避免含混,不得为重载的运算符函数设置默认值,调用时也就不得省略实参。
除了new和delete这两个较为特殊运算符以外,任何运算符如果作为成员函数重载时不得重载为静态函数。
=、[ ]、()、-以及所有的类型转换运算符只能作为成员函数重载,而且不能是针对枚举类型操作数的重载。
运算符函数的函数名是由运算符前加关键字operator构成的,在声明运算符或调用运算符时都可以用这个名称。
8.2 典范运算符的重载1.?关于分数类fractionfraction的声明和定义包含在头文件fraction.h和程序文件fraction.cpp中。
一个标准的用fraction表示的分数须满足以下复印件:①分母永远为正,分数和符号用分子表示;②分子分母互质,即总表示为最简分数。
fraction通过两个私有数据成员num和den分别保存分子和分母,并在必要时调用standardize函数进行标准化处理,以使num和den的值满足标准分数的条件。
gcd是求两个整数的最大公约数的函数,standardize在化简分数时要调用它。
2.?重载取负运算符-因为fraction用分子的符号代表整个分数的符号,因此所谓取负只需对分子num取负就可以了。
由于取负运算符-是一元运算符,当作为成员函数重载时参数表中没有参数,那个唯一的操作数以this指针的形式隐藏在参数表中。
C++中运算符重载的规则语法实例
C++中运算符重载的规则语法实例运算符重载,就是对已有的运算符重新进⾏定义,赋予其另⼀种功能,以适应不同的数据类型。
之前就知道运算符的重载就是将它重新定义,给它新的功能,为的式符合程序员的要求,⼀个例⼦就是,要将坐标相加,但是电脑不知道怎么相加,于是聪明的⼈就赋予了“+”新的定义。
然⽽⼀些严格意义上的⽤法还不是很清楚。
现在就在这总结⼀下。
⾸先运算符重载的规则如下:①、 C++中的运算符除了少数⼏个之外,全部可以重载,⽽且只能重载C++中已有的运算符。
不能重载的运算符只有五个,它们是:成员运算符“.”、指针运算符“*”、作⽤域运算符“::”、“sizeof”、条件运算符“?:”。
②、重载之后运算符的优先级和结合性都不会改变。
③、运算符重载是针对新类型数据的实际需要,对原有运算符进⾏适当的改造。
⼀般来说,重载的功能应当与原有功能相类似,不能改变原运算符的操作对象个数,同时⾄少要有⼀个操作对象是⾃定义类型。
运算符重载为类的成员函数的⼀般语法形式为:函数类型 operator 运算符(形参表){函数体;}⼲脆将⼀些运算符重新列出下⼀下:可以⽤作重载的运算符:算术运算符:+,-,*,/,%,++,--;位操作运算符:&,|,~,^,<<,>>逻辑运算符:!,&&,||;⽐较运算符:<,>,>=,<=,==,!=;赋值运算符:=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=;其他运算符:[],(),->,,(逗号运算符),new,delete,new[],delete[],->*下列运算符不允许重载:.,.*,::,?:(上⾯也说了的)下⾯给例⼦Boxoperator+(const Box&, const Box&);声明加法运算符⽤于把两个 Box 对象相加,返回最终的 Box 对象。
⼤多数的重载运算符可被定义为普通的⾮成员函数或者被定义为类成员函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
习题:2,3,4,5,7
34
return 0; }
8
C++程序设计
第10章 运算符重载
运算符重载的实质
意义:
对已有运算符赋予多重含义 使C++运算符也能用于类对象的运算
必要性
实现机制
将运算表达式转化为运算符函数的调用, 运算对象转化为运算符函数的实参。
10
运算符重载
运算符重载的要求:
操作数中至少有一个类类型
运算符重载的限制:
不能被重载的运算符(5个:., .*,::, ?:, sizeof) 不能改变运算符的优先级 不能改变运算符的结合律 不能改变运算符的操作数个数 不能创建新的运算符
11
运算符重载的方法
运算符函数
成员函数 友元函数
运算符函数形式
类型 operator 运算符(形参) { … }
12
运算符重载小结
使运算符在不同的上下文中具有不同的含义
提高了C++的可扩展性 通过函数实现,函数名由关键字operator和运算 符组成 不能改变运算符的优先级、结合律、操作数个数
最左边的操作数是类对象时,通过成员函数实现Βιβλιοθήκη 否则,运算符函数必须采用友元函数。
33
本章作业
实验10
int main() { Complex c1(10, 20), c2(20, -10), c3; c3 = c1.add(c2); //复数加 c3.print(); //复数输出 … }
7
复数类的使用
#include "complex.h“ #include <iostream.h> int main() { Complex c1(10, 20), c2(20, -10), c3; c3 = c1 + c2; ? cout<<c3<<endl; ?
5
复数类
//复数输出
void Complex::print() { if(imag>0) cout<<real<<"+"<<imag <<"i\n"; else cout<<real<<""<<imag <<"i\n"; }
6
复数类的使用
#include "complex.h“ #include <iostream.h>
思考题1
设计和实现Complex类,其满足以下要求:
属性:实部、虚部等 方法: 复数的加减乘除 复数模的计算 复数相等的比较
1
思考题
设计和实现String类,其满足以下要求:
属性:字符串等 方法: 字符串长度 字符串比较 字符串连接
2
复数类
//complex.h文件 class Complex //复数类 { public: Complex(double=0, double=0); Complex add (Complex c2); //复数加 void print(); private: double real; //实部 double imag; //虚部 };
3
复数类
//complex.cpp文件 #include "complex.h" #include <iostream.h> //构造函数 Complex::Complex(double r, double i) { real=r; imag=i; }
4
复数类
//复数加 Complex Complex::add(Complex c2) { Complex c; c.real=real+c2.real; c.imag=imag+c2.imag; return c; }