多态

运算符重载

规则:
对于自定义的类型,怎么使用系统定义好的运算符
(比如说怎么做复数的加法运算)
只需为复数类重载加法运算符
重载之后运算符的优先级和结合性都不会改变
重载运算符通过函数来实现

双目运算符重载为成员函数
形式:
函数类型 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,这样这个类就不能被继承和派生

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值