C++重载,覆盖和重写

Overload(重载):是指同一范内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,

重载不关心函数返回类型。重载一定有以下特点:

(1)相同的范围(在同一个类中);

(2)函数名字相同;

(3)参数列表不同(无论是参数类型,还是参数个数,还是参数顺序);

(4)返回值类型可以相同也可以不同,这个不作为重载的依据。

(5)virtual关键字可有可无

例如对于class A中的fun函数,以下各个fun函数版本都是属于重载,在调用的时候会根据传入参数的个数和类型来判断使用哪个版本的函数。

class A
{public:
    A(){}
    ~A(){}
    void fun(){ cout << "A::fun() is called!" << endl;}  
    void fun(int x) {cout << "A::fun(int) is called!"<<endl;}  
    void fun(double x) {cout <<"A::fun(double) is called!"<<endl;} 
    void fun(int x, double y) {cout << "A::fun(int,double) is called"<< endl;}   
    void fun (double y, int x) {cout << "A::fun(double,int) is called"<<endl;}  
};
 

Override(覆盖):是指派生类中重新定义基类中存在的函数。其函数名,参数列表,返回值类型所有必须和基类中重写的函数一致,基类中要被重写的函数

必须有virtual修饰,这个特性主要是为了实现多态特性,在调用函数的时候会根据对象的类型而不是指针或者引用的类型来判断调用哪个函数。覆盖的特征是:

(1)实现的范围不同(两个函数分别位于派生类与基类);

(2)函数名字相同;

(3)参数相同;

(4)基类函数必须有virtual 关键字。

注:重写基类虚函数的时候,会自动转换这个函数为virtual函数,因此派生类的函数之前可以加virtual也可以不加,不过为了明确,一般都会加上。

class A
{
public:
    A(){}
    ~A(){}
    virtual void fun(){ cout << "A::fun() is called!" << endl;}   
};

class B: public A
{
public:
    B() {}
    ~B() {}
    virtual void fun(){ cout << "B::fun() is called!" << endl;}  //这里的virtual可以不加 
};

int main()
{
  A a;
  B b;
  A &r1 = a; 
  A &r2 = b;
  t1.fun();   
  t2.fun();
}

上面的程序定义了两个指向A类型的引用,但是他们指向的对象不同,一个A类对象,一个B类对象,在这种情况下回根据指向对象的类型来判断调

用哪个对象的fun函数,因为a是A类对象,而b是B类对象,所以分别输出A和B的fun函数,这种情况下输出结果为:
A::fun() is called!
B::fun() is called!

但是如果上述的fun函数实现的时候没有使用virtual关键字,这就变成了下面要说的隐藏,这时候在调用fun函数的时候将不会动态的根据当前的

类型来判断调用哪个fun函数,而是根据引用或者指针的类型来判断调用哪个函数。如下程序所示:

 

class A
{
public:
    A(){}
    ~A(){}
    void fun(){ cout << "A::fun() is called!" << endl;}   
};

class B: public A
{
public:
    B() {}
    ~B() {}
    void fun(){ cout << "B::fun() is called!" << endl;} 
};

int main()
{
  A a;
  B b;
  A &r1 = a;
  A &r2 = b;
  r1.fun();   
  r2.fun();
}

上面的程序fun函数前面没有加virtual关键字,因此在r1和r2来调用fun函数的时候将根据他们自己本身的类型来调用函数,r1,r2都是A类型的

引用,因此尽管r2指向了一个B类对象,但是调用的时候还是调用A的

fun函数,上面程序的输出结果为:

A::fun() is called!
A::fun() is called!

Overwrite(重写):
隐藏,是指派生类的函数屏蔽了与其同名的基类函数,因此在派生类对象中无法再调用基类中被隐藏的函数,隐藏有以下两种情况:

(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。

(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

例如以下程序:

class A
{
public:
    A(){}
    ~A(){}
    void fun(){ cout << "A::fun() is called!" << endl;}   
};

class B: public A
{
public:
    B() {}
    ~B() {}
    void fun(int x){ cout << "B::fun(int) is called!" << endl;} 
};

int main()
{
   B b;
   b.fun();
}

虽然B是通过public的方式从A继承过来的,但是如果调用b.fun()编译器将会报错:B::fun”: 函数不接受 0 个参数,也就是说基类中的fun()已

经被隐藏了,在派生类中fun()这个函数已经不可见了,只能调用fun(int)函数,这就是隐藏,这属于上述第(1)种类型的隐藏。

对于第(2)种类型的隐藏,和在解释覆盖的时候举得例子相同,此时基类中的fun函数也是不可见的,派生类中只能调用派生类中重新定义的fun函数。

对于隐藏还有一个问题,如果在基类中有多个重载函数中版本,而在派生类中只实现了一个版本,那么基类中其他的版本都会被隐藏,如下代码所示:

class A
{
public:
    A(){}
    ~A(){}
    void fun(){ cout << "A::fun() is called!" << endl;}   
    void fun(int x) {cout << "A::fun(int) is called!" << endl;}
    void fun(int x, int y) {cout << "A::fun(int,int) is called!" << endl;}
};  

class B: public A
{
public:
    B() {}
    ~B() {}
    void fun(int x){ cout << "B::fun(int) is called!" << endl;} 
};

在B类的对象中,其实只有fun(int x)这个函数是可见的,基类中的其他版本的fun函数都是不可见的。

综上所述:重载(overload)是在一个类中实现函数的不同版本,这些函数根据输入参数的不同来决定调用哪个版本的函数,比如说一个sum函数,如

果传入两个整数就计算两个数的和,如果传入的是两个字符串就将两个字符串连接;而对于覆盖(override)来说,主要是在调用不同对象的时候,可以

动态识别对象,例如一个函数f(A & r){r.fun()},它的形参是一个指向A类的引用,这时如果实参是一个A对象,则调用A::fun(),如果传入的是B类

对象,则调用B::fun(),也就是说是动态识别的,这种可以实现真正意义的多态;对于隐藏就是简单的重新定义基类中的函数,这种情况在派生类对象

调用函数的时候只识别自己类中定义的函数。

posted @ 2018-03-29 15:39  husterxmh  阅读(166)  评论(0编辑  收藏  举报