运算符重载
例题7-1
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r1=0,double img=0):real(r1),imag(img){}
friend Complex add(const Complex &left,const Complex &right);
void show(){
cout<<real<<","<<imag<<endl;
}
};
Complex add(const Complex <,const Complex& rt){
return Complex(lt.real+rt.real,lt.imag+rt.imag);
}
int main(){
Complex c1(1,2),c2(3,4),c;
//c=c1+c2;
c=add(c1,c2);
c.show();
return 0;
}
例题7-2
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r=0,double i=0):real(r),imag(i){}
friend Complex operator +(const Complex &L,const Complex &R);
void show(){
cout<<real<<","<<imag<<endl;
}
};
Complex operator +(const Complex &L,const Complex &R){
return Complex(L.real+R.real,L.imag+R.imag);
}
int main()
{
Complex c1(1,2),c2(3,4),c;
c=c1+c2;
c.show();
return 0;
}
例题:重载+
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r=0,double i=0):real(r),imag(i){}
Complex operator +(const Complex &r);
void show(){
cout<<"("<<real<<","<<imag<<")\n";
}
};
Complex Complex::operator +(const Complex &r){
return Complex(real+r.real,imag+r.imag);
}
int main()
{
Complex c1(1,2),c2(3,4),c;
c=c1+c2;
c.show();
return 0;
}
例题:重载复数==:
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r1=0,double img=0):real(r1),imag(img){}
friend bool operator ==(const Complex &L,const Complex &R);
};
bool operator==(const Complex &L,const Complex &R){
return (L.real==R.real&&L.imag==R.imag);
}
int main()
{
Complex c1(1,2),c2(3,4),c3(1,2);
if(c1==c2){
cout<<"C1==C2"<<endl;
}else{
cout<<"C1!=C2"<<endl;
}
if(c1==c3){
cout<<"C1==C3"<<endl;
}else{
cout<<"C1!=C3"<<endl;
}
return 0;
}
把上面的重载变成 成员函数:
#include<iostream>
using namespace std;
class Complex{
double real;
double imag;
public:
Complex(double r1=0,double img=0):real(r1),imag(img){}
bool operator ==(const Complex &R);
};
bool Complex :: operator==(const Complex &R){
return (real==R.real&&imag==R.imag);
}
int main()
{
Complex c1(1,2),c2(3,4),c3(1,2);
if(c1==c2){
cout<<"C1==C2"<<endl;
}else{
cout<<"C1!=C2"<<endl;
}
if(c1==c3){
cout<<"C1==C3"<<endl;
}else{
cout<<"C1!=C3"<<endl;
}
return 0;
}
重载运算符<<为日期类Date的友元函数,输出日期.
#include<iostream>
#include<cstring>
using namespace std;
class Date{
int Y,M,D;
public:
Date(int ye,int mn,int day):Y(ye),M(mn),D(day){}
friend ostream & operator <<(ostream &out,Date &date);
};
ostream &operator<<(ostream &out,Date &date){
out<<date.Y<<" - "<<date.M<<" - "<<date.D<<endl;
return out;
}
int main()
{
Date d1(2014,01,25),d2(2017,02,35);
cout<<d1<<d2;
return 0;
}
重载运算符:++前置,++后置,<<流运算.
#include<iostream>
#include<cstring>
using namespace std;
class Time{
int H,M,S;
public:
Time (int h=0,int m=0,int s=0):H(h),M(m),S(s){}
Time &operator++();
Time operator++(int);
friend ostream &operator <<(ostream &out,Time &time);
};
Time &Time::operator++(){
S=(S+1)%60;
if(S==0){
if(M==59)
H=(H+1)%24;
M=(M+1)%60;
}
return (*this);
}
Time Time::operator++(int){
Time old=*this;
S=(S+1)%60;
if(S==0){
if(M==59)
H=(H+1)%24;
M=(M+1)%60;
}
return old;
}
ostream& operator<<(ostream &out,Time &time){
out<<time.H<<":"<<time.M<<":"<<time.S;
return out;
}
int main()
{
Time t(11,59,58);
for(int i=0;i<4;i++){
t++; cout<<t<<endl;
//cout<<t++<<endl;
}
cout<<endl;
for(int i=0;i<3;i++){
cout<<++t<<endl;
}
return 0;
}
子类与基类的兼容性
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
class Student{
string name;
int age;
double score;
public:
Student (string nm,int age,double score);
void display()const ;
};
Student::Student(string nm,int a,double s):name(nm),age(a),score(s){};
void Student::display()const{
cout<<"姓名:"<<name<<",年龄:"<<age<<",分数"<<score<<endl;
}
class Graduate:public Student{
string sy;
public:
Graduate(string name,int age,double score,string ss);
void display()const;
};
Graduate::Graduate(string nm,int a,double s,string ss):Student(nm,a,s),sy(ss){};
void Graduate::display() const{
Student::display();
cout<<"专业:"<<sy<<endl;
}
int main()
{
Student st("李强",18,95);
Graduate gt("高原",25,93,"软件工程");
st.display();
gt.display();
st=gt;
st.display();
Student &rs=gt;
rs.display();
Student *ps;
ps=>
ps->display();
return 0;
}
子类对象调用父类成员函数:
#include<iostream>
using namespace std;
class Bird{
public:
void singing(){
cout<<"bird singing...."<<endl;
}
};
class Sparrow:public Bird{
public:
void singing(){
cout<<"Sparrow jiji zha....."<<endl;
}
};
class Crow:public Bird{
public:
void singing(){
cout<<"Crow GuGuGuGuGu....."<<endl;
}
};
int main()
{
Bird bird;
Sparrow sparrow;
Crow crow;
bird.singing();
sparrow.singing();
crow.singing();
sparrow.Bird::singing();
return 0;
}
例题7-7 用循环来实现例题7-6(反例)
大家通过执行就明白了什么回事了,因为这个它只有父类指针,指着只有父类的位置来展示。
所以执行一下代码就变成全部是 Bird singing....
#include<iostream>
using namespace std;
class Bird{
public:
void singing(){
cout<<"bird singing...."<<endl;
}
};
class Sparrow:public Bird{
public:
void singing(){
cout<<"Sparrow jiji zha....."<<endl;
}
};
class Crow:public Bird{
public:
void singing(){
cout<<"Crow GuGuGuGuGu....."<<endl;
}
};
void sing(Bird *bird){
bird->singing();
}
int main()
{
Bird bird;
Sparrow sparrow;
Crow crow;
Bird *p[]={&bird,&sparrow,&crow};
//bird.singing();
//sparrow.singing();
//crow.singing();
//sparrow.Bird::singing();
for(int i=0;i<3;i++){
sing(p[i]);
}
return 0;
}
通过上面的示例缺少了个体的特性,所以引入了虚函数的概念。
虚函数的作用
引例:
#include<iostream>
using namespace std;
class Base{
public:
virtual void show(){
cout<<"showing base.\n";
}
};
class D:public Base{
public:
virtual void show(){
cout<<"showing D.\n";
}
};
int main()
{
Base base;
D d;
Base *p=&d;
p->show(); // 输出“ D ”
Base &r=d; // 输出“ D ”同上,上面用的是指针访问,而这个是引用来实现访问。
r.show();
base=d; //但是子类对象赋值基类对象后,基类对象调用的仍然是基类的虚函数.
base.show(); //输出“ Base ”
return 0;
}
例题7-9 虚函数的多态性
利用了虚函数来改善了例题7-7的弊端。
#include<iostream>
using namespace std;
class Bird{
public:
virtual void singing(){
cout<<"bird singing.....\n";
}
};
class Sparrow:public Bird{
public:
virtual void singing(){
cout<<"sparrow jijizha ....\n";
}
};
class Crow:public Bird{
public:
virtual void singing(){
cout<<"Crow GuGuGuGuGuGu ....\n";
}
};
void sing(Bird *bird){
bird->singing();
}
void sing(Bird &rb){
rb.singing();
}
void sing2(Bird bird){
bird.singing();
}
int main(){
Bird bird;
Sparrow sparrow;
Crow crow;
sing2(sparrow); //输出“Bird jijizha ..."
// 和例题7-6犯了一样的错误。只能输出父类中的singing()
sing(sparrow); //输出“sparrow jijizha ..."
Bird *p[]={&bird,&sparrow ,&crow};
for(int i=0;i<3;i++){
sing(p[i]); //依次输出“Bird/sparrow/Crow jijizha ..."
}
return 0;
}
例题7-10 人Person派生学生类,学生类派生研究生类Graduate;
#include<iostream>
#include<cstring>
using namespace std;
class Person{
char *name;
bool isMale;
int age;
public:
Person(char *name,bool isMale, int initage);
~Person(){
delete []name;
}
virtual void show()const;
};
Person::Person(char *nm,bool isM,int a):isMale(isM),age(a){
name=new char[strlen(nm)+10];
strcpy(name,nm);
}
void Person::show()const{
cout<<name<<",";
if(isMale)cout<<"男";
else cout<<"女";
cout<<","<<age<<"岁";
}
class Student :public Person{
double score;
public:
Student(char *name,bool isMale,int initAge,double initScore);
virtual void show()const;
};
Student::Student(char *nm,bool ism,int a,double s):Person(nm,ism,a),score(s){}
void Student::show() const{
Person::show();
cout<<"分数:"<<score;
}
class Graduate:public Student{
char sy[20];
public:
Graduate(char *name,bool isMale,int initage,double initScore,char spy[]);
void show()const;
};
Graduate::Graduate(char *nm,bool ism,int a,double s,char spy[]):Student(nm,ism,a,s){
strcpy(sy,spy);
}
void Graduate::show() const{
Student::show();
cout<<",专业:"<<sy<<endl;
}
void fun(Person *person){
person->show();
}
int main ()
{
Person psn("高峰",true,20);
Student st("李红",false,18,95);
Graduate gt("王涛",true,25,95,"电子学");
Person *p[]={&psn,&st,>};
for(int i=0;i<3;i++){
fun(p[i]);
cout<<endl;
}
return 0;
}
解析:基类Person中声明虚函数Show(),子类Student和Graduate中的同名函数自动成为虚函数,定义
一个fun()函数,函数形参为基类指针,函数的作用是调用show()虚函数.当基类指针指向子类时,
因调用的是虚函数,所以子类显示了学生和研究生各自的特性.
当类族中某个成员函数定义为虚函数时,对象与函数的绑定是在运行时实施的.虽然这种后绑定能够
实现运行时的多态效应,但这种绑定会增加程序运行的开销,且有若干限制条件.
( 1 )、静态成员函数不能声明为虚函数,因为静态成员属于类,不专属于某个对象。
( 2 )、内联函数不能声明为虚函数,因为内联函数在编译是已被明确的执行代码替换。
( 3 )、构造函数不能是虚函数。构造函数进行对象初始化是,对象的状态尚未完全确定。
例题7-11 虚析构函数
#include<iostream>
using namespace std;
class Base{
public:
~Base(){ //virtual ~Base() 目前没有把析构函数定义为虚函数.
cout<<"调用了 Base 析构函数"<<endl;
}
};
class D:public Base{
int *p;
public:
D(){
p=new int(5);
}
~D(){
cout<<"调用了 D 的析构函数"<<endl;
delete p;
}
};
void fun(Base *pb){
delete pb;
}
int main()
{
Base *b=new D();
fun(b);
// 若没定义虚函数则输出 “调用了Base 析构函数”;
// 若定义了则输出 “调用了 D 析构函数”
// “调用了Base析构函数”
return 0;
}
结果显示:
在基类的析构函数没有声明为虚函数时,派生类的析构函数没有调用,派生类对象动态开辟的内存
没有释放,造成了内存泄漏。
将基类的析构函数改为虚析构函数后,析构函数具有了多态效应,程序调用了不同的析构函数。
纯虚函数和抽象类
抽象类例子:
#include<iostream>
#include<cstring>
using namespace std;
class P{
char name[10];
int age;
public:
P(char name[],int age);
virtual void exercise()=0;
virtual void show();
};
class BP:public P{
int bage;
public:
BP(char name[],int age,int bage);
virtual void exercise()=0;
virtual void show();
};
class FP:public BP{
public:
FP(char name[],int age,int bage);
virtual void exercise();
};
class BsP:public BP{
public:
BsP(char name[],int age,int bage);
virtual void exercise();
};
class VP:public BP{
public:
VP(char nm[],int age,int bage);
virtual void exercise();
};
P::P(char nm[],int a):age(a){
strcpy(name,nm);
}
void P::show(){
cout<<name<<","<<age<<"岁.";
}
BP::BP(char nm[],int a,int bAge):P(nm,a),bage(bAge){}
void BP::show(){
P::show();
cout<<"球龄:"<<bage<<"年 .";
}
FP::FP(char nm[],int a,int bAge):BP(nm,a,bAge){}
void FP::exercise(){
cout<<" 踢足球.\n";
}
BsP::BsP(char nm[],int a,int bAge):BP(nm,a,bAge){}
void BsP::exercise(){
cout<<" 打篮球.\n" ;
}
VP::VP(char nm[],int a,int bAge):BP(nm,a,bAge){}
void VP::exercise(){
cout<<" 打排球.\n" ;
}
void play(P& player){
player.show();
player.exercise();
}
int main(){
FP fplay("高峰",20,8);
BsP bplay("王强",19,7);
VP vplay("张丽",18,6);
play(fplay);
play(bplay);
play(vplay);
return 0;
}
程序中基类运动员"练习"exercise()是抽象的运动,无法具体实现,所以函数exercise()声明为类Player的纯虚函数,
因此类player为抽象基类.抽象类P 不能实例化,只有子类球员BP才能具体说明球龄,但函数exercise()仍无法具体实现,
因此类BP依然为抽象类。直到子类足球运动员,篮球运动员和排球运动员是,父类的纯虚函数exercise()才能具体实现,
才可以创建各自的对象,展示各自的行为
例题7-13 将形状Shape设计成抽象类,实现运行时的多态.
#include<iostream>
using namespace std;
class Shape{
public:
virtual char *getName()=0;
virtual double getArea()=0;
};
class T:public Shape{
double width,height;
public:
T(double w,double h):width(w),height(h){}
char *getName(){
return "三角形";
}
double getArea(){
return (0.5*width*height);
}
};
class R:public Shape{
double width,length;
public:
R(double wid,double len):width(wid),length(len){}
char *getName(){
return "长方形";
}
double getArea(){
return width*length;
}
};
int main()
{
Shape *ps;
T t(10,5);
R r(2,8);
ps=&t;
cout<<"形状:"<<ps->getName()<<",面积:"<<ps->getArea()<<endl;
ps=&r;
cout<<"形状:"<<ps->getName()<<",面积:"<<ps->getArea()<<endl;
return 0;
}
模板
找到两个数,三个数里面的最大值
#include<iostream>
using namespace std;
template<typename T >T maxz(T x,T y);
template<typename S >S maxz(S x,S y,S z);
int main()
{
cout<<maxz(2,5)<<endl;
cout<<maxz(2.9,6.2)<<endl;
cout<<maxz(1,2,3)<<endl;
return 0;
}
template<typename T >T maxz(T x,T y){
return x>y?x:y;
}
template<typename S >S maxz(S x,S y,S z){
S temp=maxz(x,y);
return temp>z?temp:z;
}
模板类
#include<iostream>
using namespace std;
template <class T1,class T2>
class Myclass{
T1 x;
T2 y;
public:
Myclass(T1 a,T2 b):x(a),y(b){}
void show();
};
template <class T1,class T2>void Myclass<T1,T2>::show(){
cout<<"X="<<x<<"\tY="<<y<<endl;
}
int main()
{
Myclass<int,char>obj1(4,'w');
Myclass<double ,char >obj2(5.8,'w');
obj1.show();
obj2.show();
return 0;
}