一、函数的重载
c++中同一作用域下能够定义同名的函数(这就叫重载),但必须满足如下要求:
1、函数的参数列表必须不同,可以使参数数量不同,也可以使参数的类型不同,甚至是参数的顺序不同。
2、函数的返回值可以不同,但必须满足条件一。
3、同一作用域下的函数才会形成重载
4、常函数与非常函数也能构成重载
重载决策
当编译器遇到对重载函数的调用,它会优先选择与调用类型匹配的函数声明进行调用,这个过程叫重载决策
若没有找到完全匹配的函数声明,编译器会找到参数数量匹配但类型差异不大的函数进行调用并做隐式的类型转换。
【例】
int func(int num) { } int func(int num1,int num2) { } int main() { char ch = 48; func(ch); }
上面的例子中,最后会将变量ch做类型转换成int 然后调用 int func(int num)
如果没找到类型匹配的函数,此时又有多个函数在变量强制类型转换后能够调用,此时就会产生编译错误
【例】
void func(char *p) { } void func(long* num) { } int main() { func(1); }
二、运算符重载
C++在类中能够对大部分运算符进行重载,即将运算符的功能重新实现。
对运算符重载有以下规则:
1、对运算符的重载不改变运算符原先运算优先级,而且运算符能够操作的数也是不变的。如,一个自变运算符的重载后也只能对一个变量进行操作,不能使它变成对两个变量操作。
2、重载运算符必须有一个类类型的参数。也就是说不能 int operator+(int,int);
3、&& 和 || 重载后不再具有短路特性
4、只能对已有的运算符进行重载,不能自己定义新的运算符
5、运算符进行重载应根据新类型的实际需要,在不大幅改变运算符本身的逻辑的情况下,对运算符的功能进行加强。也就是说,重载后的运算符功能应与原来的类似。
6、不能重载的运算符有五个:成员运算符 < . > 成员指针访问运算符 < .* > 域运算符 < :: > 字节长度运算符 < sizeof > 条件运算符 < ?: >
运算符重载的语法
返回值 operator 运算符 (参数) //参数中必须有一个类类型
【例】
#include <iostream> using namespace std; class person { public: int num1; int num2; person(int x,int y) { num1 = x; num2 = y; } //friend person operator -- (person& a); friend person operator -- (person& a,int); person& operator - (person& that) { this->num1 = that.num1-that.num2; this->num2 = that.num2-that.num1; return *this; } person operator -- (void) { this->num1--; this->num2--; return *this; } void show(void) { cout << num1 << " " << num2 << endl; } }; person operator -- (person& a,int) { person b = a; a.num1--; a.num2--; return b; } int main() { person per(5,6); (--per).show(); (per--).show(); per.show(); }
在类外对运算符进行重载也是允许的,但参数里必须有一个类类型的变量
三、赋值构造
赋值构造实际上就是对运算符 = 的重载,在设计类时如果没有写赋值构造编译器会自动生成一个。
出现已初始化的两个对象之间的赋值时,便会调用赋值构造。
编译器自动生成的赋值构造只是对参数的简单赋值,如果遇到指针成员时无法拷贝指针指向的内容,而只是将指针的值赋值给左边的对象的成员。
因此我们需要自定义运算符=的重载函数,先判断自赋值,然后为指针成员释放申请内存,拷贝内容
【例】
#include <iostream> #include <string.h> using namespace std; class person { public: int num1; int num2; char *name; person(int x,int y,const char* ch) { num1 = x; num2 = y; name = new char[strlen(ch)+1]; strcpy(name,ch); } person& operator = (person& that) { if(&that != this) //检查自赋值 { delete[] this->name; //释放原先name的内存 this->name = new char[strlen(that.name)+1]; //重新为name申请内存 strcpy(this->name,that.name); num1 = that.num1; num2 = that.num2; } return *this; } void show(void) { cout << num1 << " " << num2 << " " << name << endl; } }; int main() { person per1(5,6,"jack"); person per2(2,3,"tom"); per1.show(); per2.show(); per1 = per2; per1.show(); per2.show(); }
关于自赋值
在写代码过程中可能会出现间接的自赋值情况,当delete其中一个对象的时候,再使用另一个就可能会造成错误