写在前面:
重载运算符上一次复习这个还是在期末考试的时候,当时期末考试的机试题目就是重载运算符,总的来说,重载运算符和重载函数用的还是比较多的。也是要必须掌握的。
重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。--->别人给出的定义
其实我的理解很简单,就是编译器会根据我们传入的参数不同,然后调用合适的重载函数或者运算符。
一、重载函数
函数重载就是要求在同一作用域内,几个功能类似的函数,但是他们的形参不同,这里的不同包括参数的类型,参数的个数,参数的顺序。不可以只是返回值类型不同。
#include<iostream>
using namespace std;
class A{
private:
string name;
int age;
public:
A(string n,int a):name(n),age(a){}
string getName(){return name;}
int getAge(){return age;}
};
/*
下面三个函数就构成了函数重载,编译器会根据传入参数的不同调用不同的函数。
可以是参数的个数不同,也可以是参数的顺序不同,也可以是参数的类型不同,不能仅仅是返回值类型不同。
*/
void print(A a){
cout<<a.getName()<<"的年龄是"<<a.getAge()<<endl;
}
//bool print(A a){
// cout<<a.getName()<<"的年龄是"<<a.getAge()<<endl;
// return true;
//}
string print(string str){
cout<<str<<endl;
return str;
}
void print(int n){
cout<<n<<endl;
}
int main()
{
A a("xiangxiao",21);
string s = "xiangxiao";
int n = 21;
print(a);
cout<<print(s)<<endl;
print(n);
return 0;
}
这里需要注意的是虽然在重载函数的时候函数返回值类型可以不同,但是不能仅仅是函数的返回值不同。并且我们常常并不改变函数的返回值。
除了上面提到的,当仅仅是函数的返回值不同的时候不能被重载,还有以下情况不能被重载:
- 两个函数仅仅是函数的返回值的类型不同。
-
void func(){}; int func(){ int a=0; return a;}
-
- 两个类成员函数仅仅是一个是静态成员函数一个不是,仅仅是static差别也不能重载。
-
#include<iostream> using namespace std; class A{ private: int n; public: static void func(){}; void func(){}; };
-
- 两个函数仅仅是一个有默认值一个没有默认值,或者参数个数不同,但是因为有默认值导致调用函数存在二义性。
-
//一个有默认值一个没有默认值 void func(int a){} void func(int a=10){} //或者这样 void func(int a){} void func(int a,int b=10){}
-
- 函数参数仅仅是指针和数组的差别也不构成重载,都是传地址,实际上没区别。
-
void func(int arr[]){} void func(int * p){}
-
看完我们根据print()函数传入参数不同,会调用不同的方法。是不是觉得和我们前面学的某个东西比较像,那就是我们在cout<<和cin>>的时候,好像是很多种类型都可以,这其实就是运算符重载。
二、运算符重载
我们可以重置c++中的大部分内置的运算符,来实现自定义类型的运算符。重载运算符和重载函数不同,重载运算符是带有特殊名字的函数,函数名是由关键字operator和其后要重载的运算符号构成,且与其他函数一样,有一个返回值类型和一个参数列表。
比如说我们常见的能参与+运算的只有int、double、float、string。但是对于我们自定义的一些类,如果我们想让他们相加怎么办,这个时候就可以用运算符重载了,我们重载一下+运算符,可以在类的内部重载,也可以在内外部重载,详细写法如下:
#include<iostream>
using namespace std;
class A{
private:
int a;
int b;
public:
A(){};
A(int x,int y):a(x),b(y){}
int get_a(){return a;}
int get_b(){return b;}
void set_a(int val){a=val;}
void set_b(int val){b=val;}
//运算符重载,在函数内部作为成员函数只需要一个参数
A operator+ (A &a){
A new_a;
new_a.set_a(a.a+this->a);
new_a.set_b(a.b+this->b);
return new_a;
}
};
//运算符重载,在类外部做为普通函数的时候需要两个参数
//A operator+ (A &a1,A &a2){
// A new_a;
// new_a.set_a(a1.get_a()+a2.get_a());
// new_a.set_b(a1.get_b()+a2.get_b());
// return new_a;
//}
int main()
{
A a1(1,100);
A a2(2,200);
A a3 = a2+a1;
cout<<a3.get_a()<<" "<<a3.get_b()<<endl;
string str1 = "abc";
string str2 = "def";
str1+=str2;
cout<<str1<<endl;
return 0;
}
这里我们举几个不太常规的例子:
1、提取运算符<<的重载
cout 是 ostream 类的对象。我们要实现的是能输出一个自定义类对象。
#include<iostream>
using namespace std;
class A{
private:
string name;
int age;
public:
A(string n,int a):name(n),age(a){}
string getName(){return name;}
int getAge(){return age;}
// friend ostream & operator<<(ostream &out,const A &a);
};
//因为这个是需要传入一个类对象作为参数,所以不能写作类的成员函数,可以写一个友元函数实现
//ostream & operator<<(ostream &out,const A &a){
// out<<"<A>( " << a.name << "," << a.age << " )" << endl;
// return out;
//}
//也可以直接写一个普通的外部函数,但是这需要类里面有提供给外部访问私有变量的接口。
ostream & operator<<(ostream &out, A &a){
out<<"<A>( " << a.getName() << "," << a.getAge() << " )" << endl;
return out;
}
int main()
{
A a("xiangxiao",21);
cout<<a<<endl;
return 0;
}
2、前置运算符++ 和 后置运算符++
这个运算符进行重载的时候有点区别,就是计算机在识别的时候比较难区别一个++运算符到底是前置的还是后置的,所以需要我们在重载的时候需要指定明确,约定在++运算符重载函数后面参数中添加"int",这个参数除了作为区别之外,并没有其他特殊作用。
#include<iostream>
using namespace std;
class A{
private:
int a;
int b;
public:
A(){};
A(int x,int y):a(x),b(y){}
int get_a(){return a;}
int get_b(){return b;}
void set_a(int val){a=val;}
void set_b(int val){b=val;}
//在后面添加int作为后置区别,不需要返回运算后的值,需要返回运算前的值
A operator++(int){
A temp(a,b);
this->a++;
this->b++;
return temp;
}
//前置++运算符,需要返回引用,返回的是运算和的值
A & operator++(){
this->a++;
this->b++;
return *this;
}
};
ostream & operator<<(ostream &out, A a){
out<<"<A>( " << a.get_a() << "," << a.get_b() << " )" << endl;
return out;
}
int main()
{
A a(1,100);
A b(1,100);
cout<<a++<<endl;
cout<<++b<<endl;
return 0;
}
还有更多的函数重载案例,但是比较特殊的就是这几个,所以只写了这几个。如果想看更多的可以看下面参考连接里面关于运算符重载的内容。
写在最后:
总的来说重载运算符是比较重要比较简单的部分,还是挺好理解的,加油,继续复习!
参考文章:
[2] C++运算符重载(类内、外重载)
[3] 编程狮c++