目录
重载,重写(复写,覆盖),隐藏
1.重载(函数重载)
必须在同一个类中,或者同一个源文件的普通函数之间(要求在同一个作用域中)
例子一:
class Cat //同一个类中的eat叫做重载,不同类中的eat不叫重载
{
public:
void eat()
{}
void eat(string food)
{}
}
class Bscat:public Cat
{
public:
void eat()
{}
void eat(string food,string otherfood,int n)
{}
}
例子二:
int add(int a,int b);
doble add(double a,double b);2.重写(复写,覆盖)--》发生在父子之间,多态
子类重写了父类的同名虚函数
要求一:父类的同名函数必须是虚函数
要求二:子类必须重写父类同名虚函数(返回值类型,形参类型个数都要一模一样)3.隐藏--》发生在父子之间
情况一: 子类写了跟父类同名的函数,但是子类同名函数的返回值或者参数类型个数跟父类的不相同
情况二:子类写了跟父类一模一样的函数,但是父类的函数不是虚函数
运算符重载
1.概念
C++提供了一种机制:允许程序员扩展基本运算符号的功能(让基本运算符的作用范围更广)
比如:正常情况下,加法运算只能用于整数,小数,字符
如果现在有两个猫的对象c1,c2 c1+c22.语法规则(运算符重载本质上就是个函数)
返回值 operator运算符号(形参)
{
运算符重载的代码;}
运算符重载函数的调用有两种写法
写法一:按照人类的思维习惯去调用
比如:加法 c1+c2
大于号 c1>c2
写法二:按照函数调用的写法去调用
c1.operator+(c2);
c1.operator>(c2);3.运算符重载有两种表现形式
第一种:运算符重载作为类的成员函数
默认可以使用this指针,参数就可以减少一个
第二种:运算符重载作为类的友元函数(不是成员函数)
没有this指针,所有的参数都要写上
总结:第二种写法是万能的,第一种不是万能的4.运算符重载的特点
第一个:运算符重载,函数名很奇葩,统一叫做operator运算符
第二个:运算符重载不能发明新的运算符号,只能重载已经存在的基本运算符号
operator@ --》不正确
第三个:运算符重载最好不要改变运算符原本的语义
比如: 加法运算--》心目中默认的含义是把两个东西相加,合并
第四个:如下运算符不能重载
?: :: . sizeof
5.重新认识string和cout以及cin
(1)认识string中的运算符重载
string str3=str1+str2; 重载加法
str1=str2; //重载了赋值
str1[0]; //重载了中括号(2)认识ostream中的运算符重载
第一点:输出单个变量 cout<<a; //等价于函数调用 cout.operator<<(a);
第二点:输出多个变量 cout<<a<<b<<c; //从左到右,一个个输出(每次调用运算符重载的函数,返回值都是ostream对象)
底层原理:
class ostream
{
public:
ostream &operator<<(形参)
{
输出传递过来的实参;
return *this;
}}
ostream cout;
cout.operator<<(实参); //输出单个变量
cout.operator<<(实参1).operator<<(实参2); //输出多个变量(3)认识istream中的运算符重载
第一点:输入单个变量 cin>>a; //等价于函数调用 cin.operator>>(a);
第二点:输入多个变量 cin>>a>>b>>c; //从左到右,一个个输入(每次调用运算符重载的函数,返回值都是istream对象)
底层原理:
class istream
{
public:
istream &operator>>(形参)
{
获取键盘输入的内容存放到传递过来的实参中
return *this;
}}
istream cin;
cin.operator>>(实参); //输入单个变量
cin.operator>>(实参1).operator>>(实参2); //输入多个变量6.几个特殊的运算符重载
(1)自增自减的重载
后置++和++前置
要求一:重载后置的++
Cat c1(5);
Cat c2=c1++;
返回值 operator++(int arg) //参数int为了跟前置++区分
{}
要求二:重载前置的++
Cat c1(5);
Cat c2=++c1;
返回值 operator++()
{}
(2)重载输入和输出
#include <iostream> using namespace std; class Rect { public: Rect(int _w,int _h) { w=_w; h=_h; } void show() { cout<<"w is: "<<w<<" h is: "<<h<<endl; } //把运算符重载声明成矩形类的友元函数 friend Rect operator*(int n,Rect &rect); private: int w; int h; }; //注意:operator*跟矩形类没有任何关系,就是个普普通通的函数 Rect operator*(int n,Rect &rect) { cout<<"重载乘法调用了"<<endl; rect.w=rect.w*n; rect.h=rect.h*n; return rect; } int main() { //定义矩形对象 Rect r1(5,7); /* 条件反射:把人类思维习惯写的表达式--》转换成函数调用--》可以帮助分析清楚函数该怎么写 3*r1--》3.operator*(r1)//你是来搞笑的,行不通(3不是一个对象) 正确思路:把运算符重载成Rect类的友元函数 3*r1--》operator*(3,r1) */ Rect r2=3*r1; r1.show(); r2.show(); }
上图是运算符重载作为类的友元函数。
#include <iostream>
using namespace std;
class Cat
{
public:
Cat(int _age)
{
age=_age;
}
void show()
{
cout<<"age is: "<<age<<endl;
}
//重载加法运算,让两只猫可以做加法运算
int operator+(Cat &other)
{
cout<<"加法重载被调用了,调用这个函数的对象地址是: "<<this<<endl;
return age+other.age;
}
private:
int age;
};
int main()
{
Cat c1(5);
Cat c2(7);
/*
双目运算符
分析运算符重载是如何调用的
c1+c2-->c1.operator+(c2)
c2+c1-->c2.operator+(c1)
*/
cout<<"主函数中c1地址: "<<&c1<<endl;
cout<<"主函数中c2地址: "<<&c2<<endl;
//cout<<"c1+c2 is:"<<c1+c2<<endl;
cout<<"c1+c2 is:"<<c2+c1<<endl;
}
上图是运算符重载实现两只猫的加法。
补充知识点C语言返回值和返回指针的区别
#include<stdio.h>
//返回的是值
int add(int a,int b)
{
int temp; //临时变量--》栈空间
temp=a+b;
return temp; //先备份值,然后自动释放
}
//返回的是地址(指针)
char *fun()
{
char buf[10]="hello"; //临时变量--》栈空间
printf("buf的首地址是: %p\n",buf);
return buf; //自动释放
}
int main()
{
// int m=77;
// int n=99;
// int ret=add(m,n); //返回的临时变量temp在释放之前,会在内存中备份一份值的副本
// printf("m+n is: %d\n",ret);
char *p=fun();
printf("p指向的地址是: %p\n",p);
printf("p里面存放的内容是: %s\n",p);
}
由结果可以得知两者的区别。
#include <iostream>
using namespace std;
class Cat
{
public:
Cat()
{
}
Cat(int _age)
{
age=_age;
}
void show()
{
cout<<"age is: "<<age<<endl;
}
//重载后置的++
Cat operator++(int arg) //之所以后置的++必须要加上这个int参数,原因是为了跟前置的++区分
{
cout<<"重载了后置的++"<<endl;
//定义一个临时对象
Cat temp=*this;
age=age+1;
return temp;
}
//重载前置的++
Cat operator++()
{
cout<<"重载了前置的++"<<endl;
age=age+1;
return *this;
}
private:
int age;
};
int main()
{
Cat c1(5);
//Cat c2=c1++; //单目运算符
//函数调用
Cat c2=c1.operator++(666);
c1.show();
c2.show();
Cat c3(8);
//Cat c4=++c3;
//函数调用
Cat c4=c3.operator++();
c3.show();
c4.show();
}
由上图得知重载前置与后置的区别。