c++多态与匿名对象

 多态是c++的三大特征之一,多态是指同样的消息被不同类型的对象接收时导致了不同的行为,本质上是对类的成员函数的操作,即调用了不同的函数。多态有哪些类型呢?面向对象的多态性可以分为四类:重载多态(函数重载)、强制多态(强制类型转化)、包含多态(主要通过虚函数来实现,研究类族中定义与不同类中同名函数的多态行为)、参数多态。

重载多态与强制多态属于专用多态,包含多态与参数多态属于通用多态。重载多态多表现为对普通函数或者类的成员函数的重载和运算符重载。运算符重载是对已有的运算符赋予多重定义,使相同的运算符作用于不同类型的数据时才生不同的行为。运算符重载在实现的过程中把指定的运算符转化为对运算符函数的调用,运算的对象转化为运算符函数的实参,编译器通过实参的类型来调用不同的函数,此过程在编译时完成的,属于静态绑定。不能被重载的运算符有5个:类属关系运算符“.”、成员指针运算符‘’.*”、作用域分辨率“::”、sizeof运算符、三目运算符。运算符重载形式有2种:重载为类的成员函数和类的友元函数,运算符重载的关键字为operator。

        1)重载为类的成员函数:

     函数类型 operator 运算符(形参表)

    函数体;

}
比如:重载运算符+

定义了一个基类Box,重载+运算符函数为Box的成员函数;

class Box
{
public:
Box(int xx=0,int yy=0) { radius = xx; height = yy; } ~Box() {


} int getradius() { return radius; } int getheight() { return height; } Box operator -(Box c) { return Box(radius - c.radius, height - c.height); } Box operator -() { return Box(-radius, -height); }

        Box & operator ++()//前置单目运算符

      {

           radius++;

           height++;

          return *this;

      }

Box& operator --()
{
return Box(radius--, height--);        //return *this; } Box operator ++(int)//后置单目运算符重载 { Box old = *this;

              //  ++(*this);

                return old;
} Box operator --(int) {

Box old = *this;

              --(*this);

                return old;


} Box operator + (Box c) { return Box(radius+c.radius,height+c.height);//返回一个匿名对象 } void display() { cout << radius <<","<< height << endl; } /* Box operator + (Box c) { Box d(radius + c.radius, height + c.height); return d;


} */
private:
int radius; int height;




};

由于是成员函数,在某个对象调用这个函数时,自身的数据可以直接访问,就不需要再放在参数表中传递,因此比重载为友元函数的参数个数少一个。

Box operator + (Box c)
{
return Box(radius+c.radius,height+c.height); }

调用时:Box a,b; Box c=a+b;

  2)重载为类的友元函数

友元函数可以自由地访问该类的任何数据成员,运算所需要的操作数通过函数的形参传递

friend 函数类型 operator 运算符(形参表)

{

函数体;

}          

friend Box operator + (Box c, Box d)
{

return Box(c.radius+d.radius,c.height+d.height);

}

调用时:Box a,b; Box c=a+b;

        前置运算符++ -- 与后置运算符++ --的重载函数的区别是后置运算符重载函数的参数多一个int 类型参数,这个参数在运算中不起任何作用。

对比如下:

 Box & operator ++()//前置单目运算符

      {

           radius++;

           height++;

          return *this;

      }


Box operator ++(int)//后置单目运算符重载
{
Box old = *this;

                ++(*this);又调用了一次前置单目重载函数

                return old;

}

在重载运算符+、-的函数中,都是创建一个临时的无名对象作为返回值:

Box operator + (Box c)
{

return Box(radius+c.radius,height+c.height);//返回一个匿名对象

}

函数体中的return Box();并不是对构造函数的调用,而是“创建一个临时对象并返回它”,也可以以如下的形式返回:

Box operator + (Box c)
{

Box d(radius + c.radius, height + c.height);
return d;


}

这两种方法的执行效率是完全不同的。后者的执行过程是这样的:创建一个局部对象c(这时会调用构造函数),执行return语句时会调用拷贝构造函数,将c的值拷贝到主调函数中的一个无名临时对象中。当函数operator+结束时,会调用析构函数析构对象c,然后,c消亡;前一种方法的效率明显高多了,是直接将一个无名临时对象创建到主调函数中。



在一个人员管理系统中,employee 是应该基类,manager,technician,salesman等都public继续这个基类,

如下:

class employee

{
     protected:

         char name[20];

        int individualEmpNO;

        int grade;

        float accumPay;

      static int employeeNo;

 public:

       employee();

       ~employee();

    virtual viod promote(int increment=0);

......};


class manager:public employee

{

......

 public:

        void pay(){accumPay=....}
}


class technician:public employee

{

......

 public:

        void pay(){accumPay=....}
}

class salesman:public employee

{

......

 public:

        void pay(){accumPay=....}
}


就如上面看到的那样,基类和派生类都有相同的名字的函数pay,那么可以利用一个循环结构来一次处理同一类族中不同类的对象,如下:
manager m1;technician t1; salesman s1; employee *emp[3]={&m1,&s1,&t1}
在循环体里面 emp[i]->pay();由于使用的是基类对象的指针指向派生类对象,根据类型兼容性原则,只能调用从基类继承来的函数成员,而不是派生类的新增的同名函数,因此上面调用的pay都是employee::pay();那么如何解决通过基类的指针来调用派生类的同名函数呢?解决办法就是在基类中把这个同名函数说明为虚函数虚函数是动态绑定的基础;虚函数只能出现在类声明中的函数原型声明中,而不是在成员函数实现的时候。运行过程中的多态需要满足3个条件:1)类之间满足类型兼容原则;2)声明虚函数 3)由成员函数来调用或者通过指针、引用来访问虚函数;如果是使用对象名来访问虚函数,则绑定需要在编译过程中进行(静态绑定),而无需在运行过程中进行。在重写继承来的额虚函数时,如果函数有默认形参值,千万不要重新定义不同的值,虽然虚函数是动态绑定的,但形参值确是静态绑定的,即是说通过一个指向派生类对象的基类指针,可以访问到派生类的虚函数,但默认形参值却只能来自基类的定义。

虚函数的语法声明为:

virtual 函数类型 函数名(形参表)

{

函数体;

}

在基类employee中,虚函数为 virtual void pay(){}

派生类中可以不显式声明虚函数,系统会根据该函数与基类的虚函数是否有相同的名称、参数个数、参数类型、返回值或者满足类型兼容规则的指针、引用型的返回值来判断是不是虚函数。

当基类的构造函数调用了虚函数时,不会调用派生类的虚函数,析构时同样。

如果:

void fun(Base *b)

{

delete b;

}

int main()

{

  Base *b= new Derived();

  fun(b);

}

当如上通过基类指针删除派生类对象时,系统调用的是基类的析构函数,而没有执行派生类的析构函数,倘若在派生类中有人工开辟空间的话,这时因为没有释放会造成内存泄露。

那么这么解决呢?多态!!!就是让基类的析构函数成为虚析构函数: virtual ~Base(0{}

上面提到的人员管理程序中,基类的pay()函数体为空,显得冗余。 对于这种在基类中无法实现的函数,能否在基类中只说明函数原型用来规定整个类族的统一接口形式,而在派生类中再给出函数的具体实现呢? 在c++中提供了纯虚函数来说实现这一功能。纯虚函数是一个在基类中声明的虚函数,它在基类中没有定义具体的操作内容,要求各派生类根据实际需要定义自己的版本,纯虚函数的声明格式如下:

 virtual 函数类型 函数名(参数表)=0;

带有纯虚函数的类是抽象类,抽象类不能实例化,就是不能定义一个抽象类的对象,但是可以申明一个抽象类的指针或者引用,如果抽象类派生出新类,派生类给出了所有纯虚函数的实现,则这个派生类就可以定义自己的对象,不再是抽象类。


生活那么美~~~早点睡!!!再见


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值