C++(例题集—简单解析-多态)

运算符重载

例题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;
}




猜你喜欢

转载自blog.csdn.net/z_sea/article/details/80962358
今日推荐