首页 > 代码库 > 面向对象中的顶级装备《多天吧》

面向对象中的顶级装备《多天吧》

为了便于说明多态,先从一个简单的例子说起

#include <iostream>

using namespace std;

class Parent//定义一个父类Parent类
{
public:
    //构造函数
    Parent(int a = 1)
    {
        this->a = a;
    }

    //打印Parent类的数据成员
    void print()
    {
        cout<<"a = "<<a<<endl;
    }

private:
    int a;//数据成员

};

//Parent类派生出Child类
class Child : public Parent
{
public:

    //构造函数
    Child(int b = 2)
    {
        this->b = b;
    }

      //打印Child类的数据成员
    void print()
    {
        cout<<"b = "<<b<<endl;
    }

private:
    int b;//数据成员
};

//函数参数(指针作为函数参数)
void howToPrintf(Parent *base)
{
    base->print();
}

//函数参数(引用作为函数参数)
void howToPrintf(Parent &base)
{
    base.print();//同一句话实现多种功能,有多种形态
}


void main()
{
    Parent p1;//定义Parent类的对象p1
    p1.print();//打印p1的数据成员

    Child c1;//定义Child类的对象c1
    c1.print();//打印c1的数据成员

    //使用指针访问父类对象和子类对象
    cout<<"\n使用指针访问对象:"<<endl;
   Parent *base = NULL;
    base = &p1;
    base->print();
    base = &c1;
    base->print();//没有打印子类的函数

    //使用引用访问父类对象和子类对象
    cout<<"\n使用引用访问对象:"<<endl;
    //p2是p1的引用,p2是p1的别名,p2是p1本身
    Parent &p2 = p1;
    p2.print();
    
    //c2是c1的引用,c2是c1的别名,c2是c1本身
    p2 = p1;
    p2.print();

    //使用函数访问父类对象和子类对象
    cout<<"\n使用函数访问对象(父类指针作为函数参数):"<<endl;
    //函数参数(指针作为函数参数)
    howToPrintf(&p1);
    howToPrintf(&c1);

     //使用函数访问父类对象和子类对象
    cout<<"\n使用函数访问对象(父类引用作为函数参数):"<<endl;
    //函数参数(引用作为函数的参数)
    howToPrintf(p1);
    howToPrintf(c1);

    system("pause");
}


执行结果:


程序说明:

程序中本来计划实现扥功能是调用父类的print()函数,打印父类的数据成员,调用子类的print()函数,打印子类的数据成员,然后程序中只有当直接调用父类成员函数时才打印出来父类的数据成员和子类的数据成员,间接调用中都没有实现,为了解决这个问题,需要在父类和子类都相同的成员函数前都加上关键字 virtual

加上关键字virtual后就可以实现上面的功能


修改后的代码:

#include <iostream>

using namespace std;

class Parent//定义一个父类Parent类
{
public:
    //构造函数
    Parent(int a = 1)
    {
        this->a = a;
    }

    //打印Parent类的数据成员
    virtual void print()
    {
        cout<<"a = "<<a<<endl;
    }

private:
    int a;//数据成员

};

//Parent类派生出Child类
class Child : public Parent
{
public:

    //构造函数
    Child(int b = 2)
    {
        this->b = b;
    }

      //打印Child类的数据成员
    virtual void print()
    {
        cout<<"b = "<<b<<endl;
    }

private:
    int b;//数据成员
};

//函数参数(指针作为函数参数)
void howToPrintf(Parent *base)
{
    base->print();
}

//函数参数(引用作为函数参数)
void howToPrintf(Parent &base)
{
    base.print();//同一句话实现多种功能,有多种形态
}


void main()
{
    Parent p1;//定义Parent类的对象p1
    p1.print();//打印p1的数据成员

    Child c1;//定义Child类的对象c1
    c1.print();//打印c1的数据成员

    //使用指针访问父类对象和子类对象
    cout<<"\n使用指针访问对象:"<<endl;
   Parent *base = NULL;
    base = &p1;
    base->print();
    base = &c1;
    base->print();//没有打印子类的函数

    //使用引用访问父类对象和子类对象
    cout<<"\n使用引用访问对象:"<<endl;
    //p2是p1的引用,p2是p1的别名,p2是p1本身
    Parent &p2 = p1;
    p2.print();
    
    //c2是c1的引用,c2是c1的别名,c2是c1本身
    p2 = p1;
    p2.print();

    //使用函数访问父类对象和子类对象
    cout<<"\n使用函数访问对象(父类指针作为函数参数):"<<endl;
    //函数参数(指针作为函数参数)
    howToPrintf(&p1);
    howToPrintf(&c1);

     //使用函数访问父类对象和子类对象
    cout<<"\n使用函数访问对象(父类引用作为函数参数):"<<endl;
    //函数参数(引用作为函数的参数)
    howToPrintf(p1);
    howToPrintf(c1);

    system("pause");
}


执行结果:


说明:

1、上面的代码中实现了间接访问的方式实现父类和子类的数据成员的输出,而且都是用同一个函数实现的,在面向对象中将这种同一个语句实现多种功能的方式叫做多态


2、上面的代码中出现了两个print()函数,容易将print()函数看成是函数重载,其实print()函数不是函数重载,函数重载必须是在同一个作用域中,或者同一个类中,上面的代码中的print()函数分别在两个不同的类中,所以不是函数重载,而且函数重载是指函数名相同,函数的参数不同的同一类函数,代码中函数都没有参数也不满足重载函数最基本的条件,而代码中的ShowToPrintf()函数满足函数重载的条件,所以ShowToPrintf()函数属于函数重载


多态成立的三个条件

1要有继承

2要有函数重写

3父类指针指向子类对象

面向对象中的顶级装备《多天吧》