函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
一、函数重载
#include<iostream>
#include<string>
using namespace std;
class Animal
{
public:
void eat(int apple)
{
cout << "animal eat apple:" << apple << endl;
}
void eat(int apple, char food)
{
cout << "animal eat apple and food:" << apple << " " << food << endl;
}
void eat(int apple,int corn)
{
cout << "animal eat apple and corn:" <<apple<<" "<<corn<< endl;
}
void eat(int apple, int corn) const
{
cout << "animal just eat apple and corn:" << apple << " " << corn << endl;
}
virtual ~Animal(){};
};
int main()
{
Animal pig;
const Animal dog;
pig.eat(12);
pig.eat(12,'f');
pig.eat(5,6);
dog.eat(7,8);
system("pause");
return 0;
}
另还要注意重载要在同一个范围内,例如同一个类中。(分别在基类与派生类中是不可以的)
class Stack1{
public:
void test(int a=1)
{
cout << "a="<<a << endl;
}
private:
long long value1;
};
class Stack2 :public Stack1
{
public:
using Stack1::test;//注意这个使基类同名函数重见,如果没有,使用派生类访问不了基类的同名函数(无virtual)
void test(int b,int c)
{
cout << "b="<<b << endl;
}
friend void query(Stack2 &a);
private:
int value;
};
void query(Stack2 &a)
{
cout << a.value << endl;
}
int main()
{
Stack1 haha1;
Stack2 haha2;
haha1.test();
haha2.test();
system("pause");
return 0;
}
通过在派生类中加入using Stack1::test;可以使基类的同名函数重见。
但是如果两个函数完全一样则是不可以的。
1.重载:重载从overload翻译过来,是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。(同一类)
2.隐藏:隐藏是指派生类的函数屏蔽了与其同名的基类函数。注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
3.重写:重写翻译自override,也翻译成覆盖(更好一点),是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。
二、运算符重载
C++中预定义的运算符的操作对象只能是基本数据类型,实际上,对于很多用户自定义类型,也需要有类似的运算操作。例如:
class complex
{
public:
complex(double r=0.0,double I=0.0){real=r;imag=I;}
void display();
private:
double real;
double imag;
};
complex a(10,20),b(5,8);
“a+b”运算如何实现?这时候我们需要自己编写程序来说明“+”在作用于complex类对象时,该实现什么样的功能,这就是运算符重载。运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据导致不同类型的行为。
运算符重载的实质是函数重载。在实现过程中,首先把指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参,然后根据实参的类型来确定需要调用达标函数,这个过程在编译过程中完成。
运算符重载规则如下:
① C++中的运算符除了少数几个之外,全部可以重载,而且只能重载C++中已有的运算符。
②重载之后运算符的优先级和结合性都不会改变。
③运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。一般来说,重载的功能应当与原有功能相类似,不能改变原运算符的操作对象个数,同时至少要有一个操作对象是自定义类型。
不能重载的运算符只有五个,它们是:成员运算符“.”、指针运算符“*”、作用域运算符“::”、“sizeof”、条件运算符“?:”。
运算符重载形式有两种,重载为类的成员函数和重载为类的友元函数。
运算符重载为类的成员函数的一般语法形式为:
函数类型 operator 运算符(形参表)
{
函数体;
}
运算符重载为类的友元函数的一般语法形式为:
friend 函数类型 operator 运算符(形参表)
{
函数体;
}
其中,函数类型就是运算结果类型;operator是定义运算符重载函数的关键字;运算符是重载的运算符名称。
当运算符重载为类的成员函数时,函数的参数个数比原来的操作数要少一个(后置单目运算符除外),这是因为成员函数用this指针隐式地访问了类的一个对象,它充当了运算符函数最左边的操作数。
当运算符重载为类的友元函数时,由于没有隐含的this指针,因此操作数的个数没有变化,所有的操作数都必须通过函数的形参进行传递,函数的参数与操作数自左至右一一对应。
在多数情况下,将运算符重载为类的成员函数和类的友元函数都是可以的。但成员函数运算符与友元函数运算符也具有各自的一些特点:
(1) 一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好重载为类的友元函数。
(2) 以下一些双目运算符不能重载为类的友元函数:=、()、[]、->。
(3) 类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。
(5) 若运算符所需的操作数(尤其是第一个操作数)希望有隐式类型转换,则只能选用友元函数。
(6) 当运算符函数是一个成员函数时,最左边的操作数(或者只有最左边的操作数)必须是运算符类的一 个类对象(或者是对该类对象的引用)。如果左边的操作数必须是一个不同类的对象,或者是一个内部 类型的对象,该运算符函数必须作为一个友元函数来实现。
(7) 当需要重载运算符具有可交换性时,选择重载为友元函数。
#include<iostream>
#include<string>
using namespace std;
class Animal
{
public:
Animal(int m,int n)
{
x = m;
y = n;
cout << "Animal构造函数:";
cout << "x:"<<x<<" "<<"y:"<<y << endl;
}
int getx()
{
return x;
}
int gety()
{
return y;
}
~Animal()
{
cout << "Animal析构函数" << endl;
}
int operator *(Animal &a)
{
return (this->x)*(a.x);
}
friend int operator +(Animal &a, Animal &b)
{
return a.x + b.y;
}
private:
int x;
int y;
};
int main()
{
cout << "创建动物对象" << endl;
Animal animal1(10, 30);
Animal animal2(60, 80);
cout << "测试重载+号" << endl;
int add = animal1 + animal2;
int product = animal1*animal2;
cout << "add=" << add << endl;
cout << "product=" << product << endl;
system("pause");
return 0;
}