重载
重载是面向对象三大特性中的多态(静态多态)。重载指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。
C++中的多态有静态多态和动态多态。静态多态有重载和模板,动态多态有虚函数
函数重载
函数重载是指在同一作用域内,可以有一组相同函数名,不同参数列表的函数,这组函数被称为重载函数。对函数的重载可以达到行为标识符的统一,减少程序中标识符的个数。
const关键字也可以作为函数重载的区分。
常成员函数重载:
class S {
int a;
public:
S(int x) : a(x) {}
void print() { cout << a << endl; }
void print() const;
};
void S::print() const
{
cout << “const ” << a << endl;
}
int main()
{
S a(10);
a.print(); //调用非常成员函数
const S& a1 = a;
a1.print(); //调用常成员函数
return 0;
}
运算符重载
运算符重载就是赋予已有运算符多重含义。C++通过重新定义运算符,使它能够用于特定类的对象执行特定的功能。运算符重载体现了面向对象的多态性,并且同一运算符根据不同的运算对象可以完成不同的操作。、
运算符重载规则:
- 重载运算符与预定运算符的方法完全相同,被重载的运算符不改变原来的操作数个数、优先级和结合性。
- 重载的运算符只能是运算符集合中的运算符,不能创造发明。
- 运算符的含义可以改变,但最好不改变。
- 不能改变运算符对预定义类型(基本类型)的操作方式。
- c++中不允许重载有三个操作数的运算符。
- 成员函数实现运算符重载时,运算符的左操作数为当前对象。
成员运算符函数定义语法:
class 类名
{
public:
类型 operator运算符(形参列表){
函数体;
}
}
在使用成员函数进行运算符重载时,如果重载的运算符是双目运算符,则参数表只有一个参数,如果是单目运算符,则参数表中没有参数。特殊情况除外,如++、–运算符。
赋值=、下标[]、函数调用()、成员访问->、必须重载为成员函数。
以一个字符数组运算符重载为例说一些注意事项:
class String
{
public:
String() {
memset(str, 0, sizeof(str));
}
String(const char * s) {
strcpy_s(str, s);
}
String(const String &other) {
strcpy_s(str, other.str);
}
void output() const {
cout << str << endl;
}
String & operator+=(const char *s) { //有对对象进行更改的运算符重载时建议使用&,用引用完成拷贝构造更安全
strcat_s(str, s);
return *this;
}
String & operator+=(const String &other) { //使用+=运算符对对象进行操作时,不允许出现对象+=同一对象的操作,会造成+=的循环调用
*this += other.str;
return *this;
}
bool operator==(const char * s) const{
return strcmp(str, s) == 0;
}
bool operator!=(const char * s) const{
return strcmp(str, s) != 0;
}
String operator+(const char * s) const {
String tmp = *this;
tmp += s;
return tmp;
}
String operator*(const int n) const {
String tmp = *this;
for (int i = 1; i < n; ++i)
{
tmp += this->str;
}
return tmp;
}
private:
char str[1024];
};
输入输出运算符重载
在C++库中为了方便的进行输入输出,已经对右移运算符>>和左移运算符<<进行了重载,使其能完成输出输入流。但作用对象只能是C++内置的数据类型(int、char、bool…)和标准库中所包含的类型(如string、complex…)。
这时为了更方便的对自定义数据类型进行输入输出,就需要对输入输出运算符进行重载。因为输入输出运算符要在全局范围内进行调用,所以应定义为全局函数。为了达到对类中成员的访问,输入输出的重载应定义为友员。
输入输出重载:
class A
{
private:
int a;
public:
A(int a) {
this->a = a;
}
friend istream &operator >> (istream &in, A &a) //输入流属于istream
{
in >> a.a;
return in; //返回一个流对象用于连续输入
}
friend ostream &operator<< (ostream &out, const A &a) //输出流属于ostream
{
out << a.a;
return out; //返回一个输出流对象用于连续输出
}
};
++、–运算符重载
自增自减运算符在调用前后所达成的效果不一样。在变量前使用先自增,在变量后使用赋值后自增。所以自增自减运算符重载有两种定义方式用以区分。
以自增运算符为例:
class A
{
private:
int a;
public:
A(int a) {
this->a = a;
}
A & operator++(){ //前置声明。加引用对this指向的对象可以做出实时修改
++a;
return *this;
}
A operator++(int){ //后置声明,()内int无实际意义,仅仅是用于区分使用位置。后置不需要返回引用,引用的实时性对返回的temp没有作用
A temp = *this;
++a;
return temp;
}
}
赋值运算符重载
赋值运算符的重载处理方法与拷贝构造函数处理方法完全相同。系统会提供默认的赋值运算符,需要判断是否需要实现赋值运算符重载或删除赋值运算符重载。一般来讲,赋值运算符与拷贝构造成对出现。
A & operator=(const A &other){ //自己实现赋值运算符重载
A.a = other.a;
return *this;
}
A & operator=(const A &other) = delete; //不实现赋值运算符重载
下标运算符重载
返回值类型 & operator[](int index); //可以对元素进行修改
const 返回值类型 & operator[](int index) const; //不可以对元素进行修改
函数调用运算符(仿函数)
struct Less //此处用结构体代表类使访问权限默认公有
{
bool operator() (int a, int b) const {
return a < b;
}
};
struct Greater
{
bool operator() (int a, int b) const {
return a > b;
}
};
int main()
{
Less a;
if(a(1,2)){ //a为对象名,不是函数名
cout << "less" << endl
}
Graeter b;
if(b(1,2)){
cout << "Greater" << endl
}
return 0;
}
成员访问运算符
class A
{
public:
void test() const{
cout << "test" << endl;
}
A * operator->(){
return this;
}
}
int main()
{
A a1;
a1->test(); //对象调用了成员函数test
return 0;
}