运算符重载
规则:
对于自定义的类型,怎么使用系统定义好的运算符
(比如说怎么做复数的加法运算)
只需为复数类重载加法运算符
重载之后运算符的优先级和结合性都不会改变
重载运算符通过函数来实现
双目运算符重载为成员函数
形式:
函数类型 operator 运算符(形参)
{
}
例如:重载操作数B为类的成员函数,使之能实现
oprd1Boprd2,其中oprd1为类A的对象,B被重载为A的成员函数形参类型应该是oprd2所属类型
plural operator +(const plural &k)
{
return plural(a+k.a,b+k.b);//直接构造临时无名对象,不用再构造一个
}
重载后oprd1Boprd2相当于oprd1.operator B(oprd2)
例子:
#include<iostream>
using namespace std;
class plural
{
private :
int a, b;
public:
plural(int aa=0,int bb=0):a(aa),b(bb){}
plural(const plural& p)
{
a = p.a;
b = p.b;
}//记得写复制构造函数
void showplural();
int geta() { return a; }
int getb() { return b; }
plural operator +(const plural &k)
{
return plural(a+k.a,b+k.b);//直接构造临时无名对象,不用再构造一个
}
};
void plural::showplural()
{
if (b > 0)
cout << "这个复数是" << a << "+" << b << "i" << endl;
else
cout << "这个复数是" << a<< b << "i" << endl;
}
int main()
{
plural x(1, 2);
plural y(3, 4);
x.showplural();
y.showplural();
(x + y).showplural();
}
也可以构造复数加实数
单目运算符重载为成员函数:
如果要重载U为成员函数,使之实现U oprd;其中oprd为A类对象,则U应该重载为A的成员函数,无形参;定义为A. operator U();
重载后,U oprd 相当于oprd. operator U()
而后置运算符也是这样定义A. operator U(),那怎么区分呢
这就要利用参数表了,给一个参数表里加的参数
#include<iostream>
using namespace std;
class clock
{
public:
clock(int hour = 0, int minute = 0, int second = 0);
void showtime()const;
clock &operator ++();
clock operator ++(int);
private:
int h, m, s;
};
void clock::showtime()const
{
cout << "现在是北京时间" << h << ":" << m << ":" << s << endl;
}
clock::clock(int hour , int minute , int second )
{
h = hour, m = (minute), s = (second); //其实这里还要判断输入数据的合理性,鉴于这里不突出,就省了
}
clock & clock::operator ++()//返回的是自己,也就是说,返回以后可能还要通过什么操作来用这个返回值,所以用引用所以是个引用,使修改返回值时能直接对当前对象操作,(返回的是引用,可以当左值)
{
s++;
if (s >= 60)
{
s = 0;
m++;
}
if (m >= 60)
{
m = 0; h = (h + 1) % 24;//这里保证超过24小时后的
}
return *this;//因为返回值是一个时钟,所以把现在的时钟返回
}
clock clock::operator++(int)//返回的是旧的值,是myclock的一个副本,没有意义的,不多修改,但可以用它再调用一下自己的函数或者把他赋值给一个新时钟,所以不用引用,(返回的是值,不能当左值)
{
clock old = *this;
++ (*this);//直接调用上面定义好的++来完成这里的++,避免要修改小时制使忘了修改这里
return old;//由于是前置,所以返回的是没加之前的值
}
int main()
{
clock myclock(23, 59, 59);
cout << "刚开始的时钟" << endl;
myclock.showtime();
cout << "后置++的时钟" << endl;
(myclock++).showtime();//用完这个showtime老的时钟就失去意义了,返回的是老时钟;
cout << "前置++后的时钟" << endl;
(++myclock).showtime();//系统会根据你++的位置知道你要调用哪个,,所以不用传参数
return 0;
}
运算符重载为非成员函数()
如果我们面临的一个运算的左操作数不是类的成员对象,重载运算符函数就不能是类的成员函数了(如实数加复数,实数在加号左边 ,就不行了)
1:形参要列出所有的操作数,且形参的左右顺序也是算术中的左右顺序
2:单目还是在形参里加一个整数形参来区分前置后置
3:至少有一个自定义类型的参数
4:函数可能要操作某个类的私有成员,则把这个函数声明为这个类的友元(为了提高运算效率)
重载"<<"这个运算符,使cout整个输出一个复数对象,插入运算符只能重载为类外的成员函数
原因: << 是系统里预定好的一个类库里的输出流的对象,不是我们自定义的对象,所以我们无法从输出流类里面去加一个重载的成员函数,所以我们在类外重载
<<左操作数是输出流对象的常引用,右操作数是复数类对象的常引用,要求返回输出流的引用,有何用?
cout<<a<<b;第一次a调用了<<,返回了一个输出流的引用,这样第二个<<的左边也有了操作数,就实现了这个操作
ostream &operator <<(ostream& out, const plural& c)
{
if (c.b > 0)
out << "这个复数是" << c.a << "+" << c.b << "i" << endl;
else
out << "这个复数是" << c.a << c.b << "i" << endl;
return out;//引用返回后还是一个流的对象
}
cout << (A + B) << (A - B) << endl;
#include<iostream>
using namespace std;
class plural
{
private:
int a, b;
public:
plural(int aa = 0, int bb = 0) :a(aa), b(bb) {}
plural(const plural& p)
{
a = p.a;
b = p.b;
}
friend plural operator +(const plural &A, const plural &B);
friend plural operator -(const plural &A, const plural &B);
friend ostream &operator <<(ostream& out, const plural& c);//<<是ostream类里的对象
int geta() { return a; }
int getb() { return b; }
};
plural operator + (const plural &A, const plural &B)//传引用的效率高
{
return plural(A.a + B.a, A.b + B.b);
}
plural operator -(const plural &A, const plural &B)
{
return plural(A.a - B.a, A.b - B.b);
}
ostream &operator <<(ostream& out, const plural& c)
{
if (c.b > 0)
out << "这个复数是" << c.a << "+" << c.b << "i" << endl;
else
out << "这个复数是" << c.a << c.b << "i" << endl;
return out;//引用返回后还是一个流的对象
}
int main()
{
plural A(1, 2), B(2, 3);
cout << (A + B) << (A - B) << endl;
return 0;
}
抽象类:
一些类代表着某些抽象的东西,一些功能无法实现(比如定义一个二维图形类,就不知道怎么求面积了,因为图形很多)
纯虚函数:
在基类中定义的函数,它在基类中没有定义具体的操作内容,要求派生类根据自己的需求定义不同的版本:
virtual 函数类型 函数名 (参数表)=0;(表示没有函数体)
只要带有带有纯虚函数的类叫抽象类,抽象类不能定义对象的,它做基类用
虽然不能定义抽象类的对象,但是可以定义抽象类的指针,用来指向它的派生类
c++11中提供的override和final
有时候我们想写一个原型一样的虚函数来覆盖基类中的虚函数,但是有时候我们写的原型可能不太一致(可能少了个const什么的),这是编译器不会报错,编译器不知道我们的意图,所以这种错误实现不了多态性。
而c++11中能发现这种错误,给我们指出来,不过就是用override说明,而不是virtual,用override说明的虚函数,原型一定要和基类的一样,不然会报错
有的类的一些功能不希望被派生类覆和修改,这时候在函数后使用final说明,这样这个函数就不会被覆盖了,也可以在类后用final,这样这个类就不能被继承和派生