文章目录
- 面向对象之多态
- 运算符重载
- 运算符重载简介
- 双目运算符重载
- 重载单⽬运算符
- 重载流插⼊与流提取运算符
- 重载()
- 不同类型间转换
面向对象之多态
多态性(polymorphism)是⾯向对象程序设计的⼀个重要特征。利⽤多态性可以设计和实现⼀个易于扩展的系统 。
C++程序设计中,多态性是指具有不同功能的函数可以⽤同⼀个函数名,这样就可以⽤⼀个函数名调⽤不同内容的函数。
在⾯向对象⽅法中⼀般是这样表述多态性的: 向不同的对象发送同⼀个消息,不同的对象在接收时会产⽣不同的⾏为(即⽅法)。也就是说,每个对象可以⽤⾃⼰的⽅式去响应共同的消息
多态分为:静态多态和动态多态
静态多态是通过函数的重载来实现的,用户在调用重载函数时,根据传参的个数或类型的不同,该同名函数所作出的不同反应
静态多态是因为该代码在编译时,编译器根据形参个数或类型就能够确定匹配哪一个函数
动态多态性是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。动态多态性是通过虚函数实现的。
运算符重载
运算符重载简介
在 C++ 中,当操作数包含类对象时,运算符操作实际上是一个函数。由此可见,对于类对象而言,操作符运算实际上就是调用对应的类方法,但要注意,除了赋值运算操作符(即等号=)是默认的之外,其余的大多数运算符都是需要定义了才能用的,否则会被判定为非法。
引⼊运算符重载是为了实现类的静态多态性。运算符重载是对已有的运算符赋予多重含义,使⽤⼀个运算符作⽤与不同类型的数据时导致不同的⾏为。
运算符重载的⽅法是定义⼀个重载运算符的函数,在需要执⾏被重载的运算符时,系统就⾃动调⽤该函数,以实现相应的运算。
运算符重载有两种⽅式:
- 类内重载(运算符重载函数作为类的成员函数)
- 类外重载
运算符重载运算符的函数⼀般格式如下 :
函数类型 operator 运算符名称(形参列表)
{函数体
}
运算符重载的规则:
- C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载。
- C++中绝大部分的运算符允许重载。不能重载的运算符只有5个:
- .(成员访问运算符)
- .*(成员指针访问运算符)
- ::(域运算符)
- sizeof(长度运算符)
- ?:(条件运算符)
前两个运算符不能重载是为了保证访问成员的功能不能被改变
重载不能改变运算符运算对象(即操作数)的个数
● 重载不能改变运算符的优先级别和结合性
● 重载运算符的函数不能有默认的参数,否则就改变了运算符参数的个数,与第3条冲突。
● 重载的运算符必须和⽤户定义的⾃定义类型的对象⼀起使⽤,其参数⾄少应有⼀个是类对象(或类对象的引⽤)。也就是说,参数不能全部是C++的标准类型,以防⽌⽤户修改⽤于标准类型数据的运算符的性质 。
● ⽤于类对象的运算符⼀般必须重载,但有两个例外,运算符“=”和“&”不必⽤户重载 。
① 赋值运算符(=)可以⽤于每⼀个类对象,可以利⽤它在同类对象之间相互赋值。
② 地址运算符&也不必重载,它能返回类对象在内存中的起始地址。
● 重载运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既⾮类的成员函数也不是友元函数的普通函 (最后⼀种情况较为少⽤)
双目运算符重载
类内重载,双目运算符重载的第一个操作数传递给隐形参数this,函数只显示说明一个参数,该形参是运算符的右操作数。
class stu
{public:string name;int math;int chinese;stu(string sname, int m, int c);//重载两个stu对象相加int operator+(const stu& pp) //运算符类内重载{int sum = 0;sum = this->math + pp.math + this->chinese + pp.chinese;return sum;}//重载stu和⼀个int相加stu operator+(const int num){int sum = 0;this->math += num;this->chinese+= num;return *this;}
};
stu::stu(string sname, int m, int c)
{this->name = sname;this->math = m;this->chinese = c;
}
int main()
{stu s1("yaoyao", 50, 60);stu s2("leilei", 30, 70);cout << s1 + s2 << endl; //s1 + s2 相当于 s1 对象调⽤+⽅法并且传⼊参数时 s2 对象stu temp=s1 + 20;cout << temp.math << temp.chinese << endl;return 0;
}
重载单⽬运算符
单⽬运算符只有⼀个操作数,如!a, -b, &c, *p,还有最常⽤的++i和–i等。重载单⽬运算符的⽅法与重载双⽬运算符的⽅法是类似的。
但由于单⽬运算符只有⼀个操作数,因此运算符重载函数只有⼀个参数,如果运算符重载函数作为成员函数,则还可省略此参数。
示例:
#include <iostream>
using namespace std;
class Time
{public:Time( ){minute=0;sec=0;} //默认构造函数Time(int m,int s):minute(m),sec(s){ } //构造函数重载Time operator++( ); //声明前置⾃增运算符++重载函数Time operator++(int); //声明后置⾃增运算符++重载函数void display( ){cout<<minute<<":"<<sec<<endl;} //定义输出时间函数private:int minute;int sec;
};
Time Time::operator++( ) //定义运算符重载函数
{if(++sec>=60){sec-=60; //满60秒进1分钟++minute;}return *this; //返回当前对象值
}
//多传⼊⼀个参数,让c++编译器知道,这是两个不同的函数,避免出现重定义的情况
Time Time::operator++(int) //定义运算符重载函数
{if(sec++>=59){sec-=60; //满60秒进1分钟++minute;}return *this; //返回当前对象值,⽬的是可以⽤Time类型变量接收
}
int main( )
{Time time1(34,0);for (int i=0;i<61;i++){//++time1; //调⽤成员函数的运算符格式time1.operator++();time1++;time1.display( );}return 0;
}
重载流插⼊与流提取运算符
在C++中,标准库本身已经对左移运算符<<和右移运算符>>分别进⾏了重载,使其能够⽤于不同数据的输⼊输出,但是输⼊输出的对象只能是 C++ 内置的数据类型(例如 bool、int、double 等)和标准库所包含的类类型(例如 string、
complex、ofstream、ifstream 等)。
如果我们⾃⼰定义了⼀种新的数据类型,需要⽤输⼊输出运算符去处理,那么就必须对它们进⾏重载
对“<<”和“>>”重载函数形式如下:
istream & operator>>(istream &, ⾃定义类&);
ostream & operator<<(ostream &, ⾃定义类&);
重载>>函数说明:
参数1:必须是istream&类型(即为istream对象的引⽤),
参数2:要进⾏输⼊操作的类
函数类型也必须为istream&类型
注意:
只能将重载“>>”和“<<”的函数作为友元函数,⽽不能静它们定义成员函数。
重载插⼊运算符与提取运算符例⼦:
#include <iostream>
using namespace std;
class Time
{public:Time( ){minute=0;sec=0;} //默认构造函数Time(int m,int s):minute(m),sec(s){ } //构造函数重载friend ostream& operator<<(ostream& ,Time &t); //重载插⼊运算符号friend istream& operator>>(istream& ,Time &t); //重载提取运算符>>void display( ){cout<<minute<<":"<<sec<<endl;} //定义输出时间函数private:int minute;int sec;
};
ostream& operator << (ostream & out,Time &t) //定义重载<<输出函数
{out<<t.minute<<":"<<t.sec<<endl;return out;
}
istream& operator>>(istream& in ,Time &t)
{in>>t.minute>>t.sec;return in;
}
int main( )
{Time time1(34,0); cin>>time1;//time1.display();cout<<time1;
重载()
重载后的使⽤⽅式⾮常像函数的调⽤,因此称为仿函数
不同类型间转换
我们都知道标准类型数据间可以进⾏转换,C++也提供了显式的类型转换,其形式为:类型名(数据);对于标准类型转换,编译系统知道如何转换,但是对于⽤户⾃⼰声明的类型,编译系统不知道如何转换,这个时候就需要定义专⻔的函数来处理。
1.⽤转换构造函数进⾏不同数据类型的转换
如果需要将系统预定义的数据类型转换为类类型的会⽤到转换构造函数
//转换构造函数的作⽤就是将以个其他类型转换成⼀个类对象。
#include <iostream>
#include <algorithm>
using namespace std;
class Student
{public:float score;int age;public:Student(void){age = 18; score = 0.2f;}Student(float s){age = 0; score = s;//转换构造函数只有⼀个参数cout<<"ljs"<<endl;}friend float operator+(Student&a,float p);
};
float operator+(Student &a,float p)
{return a.score+p;
}
int main()
{Student stu1,stu2;stu2=stu1+ Student(3.2f);//3.2f; //不同类型相加会发⽣隐式转换cout << stu2.score<< endl;return 0;
}
//
ljs3.4class Student
{public:float score;int age;public:Student(void){age = 18; score = 0.2f;}Student(float s){age = 0; score = s;cout<<"ljs"<<endl;}friend float operator+(Student&a,Student b);//重载+,返回float类型};
float operator+(Student &a,Student b)
{return a.score+b.score;
}
int main()
{Student stu1,stu2;float pp=stu1+Student(5.3f);//3.2f;cout <<pp<< endl;return 0;
}
转型构造函数可以将其它类型的参数转换为类类型,如果我们要进⾏相反的转换过
程,将类类型转换为其它数据类型,则需重载转型操作符。
转型操作符重载函数的声明语法如下:
operator 类型名 ();
转型操作符重载函数有⼏点需要注意的:
函数没有返回类型;
虽然没有返回类型但是函数体中必须有return语句,其返回类型是由类型名来指定的;
转型操作符重载函数只能以类的成员函数的形式进⾏重载,⽽不能以友元函数或顶层函数的形式进⾏重载,
转换函数不能有参数
C++中的operator主要有两个作⽤,⼀是操作符的重载,⼀是操作符的转换
class Student
{private:float score;int age;public:Student(void){age = 18; score = 0;}Student(int a, float s){age = a; score = s;}operator float(){return score;}//转换函数⼀般不应该改变被转换的对象,因此转换操作符通常应定义为 const 成员;
};
int main()
{Student stu1(18, 86), stu2(18, 97.5);float f;f = 6.75 + stu2; //当需要的时候,编译器会⾃动调⽤这些函数cout << f << endl;return 0;
}
只要存在转换,编译器将在可以使⽤内置转换的地⽅⾃动调⽤它,⽐如隐式转换或强制转换(类名(指定类型的数据))
