C++学习笔记(3)-重载与多态

C++中的函数重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。
例子:

#include <iostream>
using namespace std;

class printData 
{
   public:
      void print(int i) {
        cout << "Printing int: " << i << endl;
      }

      void print(double  f) {
        cout << "Printing float: " << f << endl;
      }

      void print(char* c) {
        cout << "Printing character: " << c << endl;
      }
};

int main(void)
{
   printData pd;

   // Call print to print integer
   pd.print(5);
   // Call print to print float
   pd.print(500.263);
   // Call print to print character
   pd.print("Hello C++");

   return 0;
}

结果:

Printing int: 5
Printing float: 500.263
Printing character: Hello C++

函数重载只要函数传入变量不同即可。

C++中的运算符重载

格式:

<返回类型说明符> operator <运算符符号>(<参数表>)  
{  

     <函数体>  

}  

当运算符重载为类的成员函数时,函数的参数个数比原来的操作个数要少一个;当重载为类的友元函数时,参数个数与原操作数个数相同。原因是重载为类的成员函数时,如果某个对象使用重载了的成员函数,自身的数据可以直接访问,就不需要再放在参数表中进行传递,少了的操作数就是该对象本身。而重载为友元函数时,友元函数对某个对象的数据进行操作,就必须通过该对象的名称来进行,因此使用到的参数都要进行传递,操作数的个数就不会有变化。
例子:

#include <stdio.h>
using namespace std;

class Point    
{    
private:    
    int x;   
public:    
    Point(int x1)  
    {   x=x1;}    
    const Point operator+(const Point& p);//使用成员函数重载加号运算符  
    friend const Point operator-(const Point& p1,const Point& p2);//使用友元函数重载减号运算符  
};    

const Point Point::operator+(const Point& p)  
{  

    return Point(p.x+x);  
}  

Point const operator-(const Point& p1,const Point& p2)  
{  
    return Point(p1.x-p2.x);  
} 
int main()
{
    Point a(1);    
Point b(2);  
a+b;  //正确,调用成员函数  
a-b;  //正确,调用友元函数  
a+1;  //正确,先调用类型转换函数,把1变成对象,之后调用成员函数  
a-1;  //正确,先调用类型转换函数,把1变成对象,之后调用友元函数  
1+a;  //错误,调用成员函数时,第一个操作数必须是对象,因为第一个操作数还有调用成员函数的功能  
1-a;  //正确,先类型转换 后调用友元函数  
    return 0;
}

可以写成

#include <stdio.h>
using namespace std;

class Point    
{    
private:    
    int x;   
public:    
    Point(int x1)  
    {   x=x1;}    
    const Point operator+(const Point& p)
    {
      Point t(0);
      t.x=this->x+p.x;
      return t;

    }//使用成员函数重载加号运算符  
    friend const Point operator-(const Point& p1,const Point& p2)
    {
      Point m(1);
      m.x=p1.x+p2.x;
      return m;
    }//使用友元函数重载减号运算符  
};    

int main()
{
    Point a(1);    
Point b(2);  
a+b;  //正确,调用成员函数  
a-b;  //正确,调用友元函数  
a+1;  //正确,先调用类型转换函数,把1变成对象,之后调用成员函数  
a-1;  //正确,先调用类型转换函数,把1变成对象,之后调用友元函数  
1+a;  //错误,调用成员函数时,第一个操作数必须是对象,因为第一个操作数还有调用成员函数的功能  
1-a;  //正确,先类型转换 后调用友元函数  
    return 0;
}

注意,应当注意在类中应该使用this指针,并且一旦构造函数是初始化函数,生命的函数一定要设定一个值,不然会报错

多态

当基类和派生类有相同的函数名,如果不使用“virtual”关键字,那么将会导致基类和派生类都是调用基类中的函数,例子如下:

#include <iostream> 
using namespace std;

class Shape {
protected:
    int width, height;
public:
    Shape(int a = 0, int b = 0)
    {
        width = a;
        height = b;
    }
    int area()
    {
        cout << "Parent class area :" << endl;
        return 0;
    }
};
class Rectangle : public Shape {
public:
    Rectangle(int a = 0, int b = 0) :Shape(a, b) { }
    virtual int area()
    {
        cout << "Rectangle class area :" << endl;
        return (width * height);
    }
};
class Triangle : public Shape {
public:
    Triangle(int a = 0, int b = 0) :Shape(a, b) { }
    int area()
    {
        cout << "Triangle class area :" << endl;
        return (width * height / 2);
    }
};
// 程序的主函数
int main()
{
    Shape *shape,sha;
    Rectangle rec(10, 7),*rect;
    Triangle  tri(10, 5),*tria;

    // 存储矩形的地址
    shape = &rec;
    // 调用矩形的求面积函数 area
    shape->area();
    //正常调用
    rec.area();
    //同类型指针
    rect = &rec;
    rect->area();
    cout << endl;

    //rect = &sha;   不能够将基类的地址赋值给派生类型的指针

    // 存储三角形的地址
    shape = &tri;
    // 调用三角形的求面积函数 area
    shape->area();
    //正常调用
    tri.area();
    //同类型指针
    tria = &tri;
    tria->area();
    return 0;
}

执行的结果如下:

Parent class area :
Rectangle class area :
Rectangle class area :

Parent class area :
Triangle class area :
Triangle class area :

导致错误输出的原因是,调用函数 area() 被编译器设置为基类中的版本,这就是所谓的静态多态,或静态链接 - 函数调用在程序执行前就准备好了。有时候这也被称为早绑定,因为 area() 函数在程序编译期间就已经设置好了。
此外派生类变量的地址能够赋值给基类指针,但是基类变量的地址不能赋值给派生类地址,同态仅仅发生在派生类变量的地址赋值给基类指针的情况下,如果派生类变量的地址赋值给派生类变量的指针就不会发生这种情况例如

#include <iostream.h>
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3 (surprise!)
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
}

但现在,让我们对程序稍作修改,在 Shape 类中,area() 的声明前放置关键字 virtual,如下所示:

class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      virtual int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

结果如下:

Rectangle class area :
Rectangle class area :
Rectangle class area :

Triangle class area :
Triangle class area :
Triangle class area :

注意!virtual针对的只是函数指针类型,当一个派生类的指针访问的时候才会出现以上的问题,当使用“.”来访问的时候,那么输出的还是变量对应的类型
此外,virtual只是解决同态问题,shape的类型仍然可以调用

如果加上

shape = &sha;
    shape->area();
    sha.area();
    cout << endl;

那么输出是:

Parent class area :
Parent class area :

Rectangle class area :
Rectangle class area :
Rectangle class area :

Triangle class area :
Triangle class area :
Triangle class area :

参考文献:http://blog.csdn.net/djh512/article/details/8973606
virtual 的作用效果是对后面的有效例如

#include <iostream> 
using namespace std;

class GrandFather
{
public:
    GrandFather() {}
    void fun()
    {
        cout << "GrandFather call function!" << endl;
    }
};

class Father : public GrandFather
{
public:
    Father() {}
     void fun()
    {
        cout << "Father call function!" << endl;
    }
};


class Son : public Father
{
public:
    Son() {}
    void fun()
    {
        cout << "Son call function!" << endl;
    }
};

void print(GrandFather* father)
{
    father->fun();
}

int main()
{
    Father * pfather = new Son;
    pfather->fun();
    GrandFather * pgfather = new Father;
    print(pgfather);
    return 0;
}

输出的结果是

Father call function!
GrandFather call function!

如果在class GrandFather类中加入virtual,那么以他为基础的派生类都有效,即如果将class GrandFather加入virtual,如下

class GrandFather
{
public:
    GrandFather() {}
    virtual void fun()
    {
        cout << "GrandFather call function!" << endl;
    }
};

输出的是

Son call function!
Father call function!

如果在class Father中加入virtual,其他的都不加,那么其结果是

Son call function!
GrandFather call function!

如果在 class Son加上virtual,其结果是

Father call function!
GrandFather call function!

如果加入两个virtual 如下

#include <iostream> 
using namespace std;

class GrandFather
{
public:
    GrandFather() {}
    void fun()
    {
        cout << "GrandFather call function!" << endl;
    }
};

class Father : public GrandFather
{
public:
    Father() {}
    virtual void fun()
    {
        cout << "Father call function!" << endl;
    }
};


class Son : public Father
{
public:
    Son() {}
    virtual void fun()
    {
        cout << "Son call function!" << endl;
    }
};

void print(GrandFather* father)
{
    father->fun();
}

int main()
{
    Father * pfather = new Son;
    pfather->fun();
    GrandFather * pgfather = new Father;
    print(pgfather);
    return 0;
}

结果是

Son call function!
GrandFather call function!

也就是说,virtual只能够向派生类的方向有效,只能向“上”,对“下”是无效的,基类在“下”,派生类在“上”

纯虚函数主要是在基类中声明以便在派生类中使用,他不能够被初始化。
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
 virtual void funtion1()=0
此外,不能对友元函数使用虚函数处理;
对每个派生类中的相同函数,都要进行声明
例如

#include <iostream> 
using namespace std;

class GrandFather
{
public:
    GrandFather() {}
    virtual void fun() = 0;
};

class Father : public GrandFather
{
public:
    Father() {}
    void fun()
    {
        cout << "Father call function!" << endl;
    }
};


class Son : public Father
{
public:
    Son() {}
    void fun()
    {
        cout << "Son call function!" << endl;
    }
};

void print(GrandFather* father)
{
    father->fun();
}

int main()
{
    Father * pfather = new Son;
    pfather->fun();
    GrandFather * pgfather = new Father;  //指针允许
    GrandFather *gp1;//不指针允许
    GrandFather  gp2;//不能够实例化
    print(pgfather);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值