cpp函数覆写与重载、隐藏的区别以及多态特性的实现

⌚Time: 2021-09-01 17:47:53

👨‍💻Author: Jack Ge

一、覆写、重载与隐藏的区别:

1.1 覆写(重写)、重载与隐藏的定义

覆写(override):是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。

重载(overload):是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。

隐藏(hide):是指派生类的函数屏蔽了与其同名的基类函数,只要函数名称是相同的,不管参数列是否相同,基类函数都会被隐藏。

1.2 重载与覆写

重载的函数必须在相同类域,是编译时确定函数地址,与函数模版同属于编译时多态,在编译时就已经根据函数的参数特征确定了要使用哪个函数。

函数覆写在不同类域实现,即派生类函数覆写基类函数,是运行时多态,通过虚函数表和动态绑定机制,在运行时通过查找子类虚函数表来动态调用子类函数。

重载函数的参数的类型,个数,顺序至少要有一个不同,重载不关心返回值,而重写的函数的参数、类型,个数,顺序以及返回值必须要与基类函数一致。

1.3 重载与隐藏

重载是在相同类域,而隐藏是在不同类域,比如基类与派生类同名函数就不是重载而是隐藏,而在基类中两个同名函数就是重载

重载的函数除了名称外,其他特征(如参数类型、个数或顺序)不能完全一样。而隐藏可以派生类的函数与基类的函数的名称以及其他特征一模一样。

1.4 覆写与隐藏

覆写与隐藏的区别请参照我的另一篇文章:c++中的覆写和隐藏

当派生类与基类函数同名,通常需要使用的是派生类函数。虽然隐藏默认也是调用派生类函数,隐藏父类函数,但是与隐藏比,覆写具有以下的好处:

创建一个基类A,编写一个函数fun(),要求调用所有基类A的派生类的function方法

如果是覆写,那么只需将fun()的参数设为基类指针而传入派生类地址,函数内调用基类的function方法,就可以实现对传入的派生类function方法的调用,这就是c++的多态特性

#include<iostream>
using namespace std;
 
class A{
    public:
        virtual void function(){
            cout<<"A::function"<<endl;
        }
};
class B:public A{
    public:
        virtual void function(){
            cout<<"B::function"<<endl;
        }
 
};
class C:public A{
 
    public:
        virtual void function(){
            cout<<"C::function"<<endl;
        }
 
};
//只需接收基类传参
void fun(A* a){
    a->function();
}
int main(){
    B b;
    C c;
    fun(&b);
    fun(&c);
    return 0;
}
 

而如果是隐藏,fun函数需要为每一个派生类类型设定对应的形参

#include<iostream>
using namespace std;
 
class A{
    public:
        void function(){
 
            cout<<"A::function"<<endl;
        }
};
class B:public A{
    public:
        void function(){
            cout<<"B::function"<<endl;
        }
 
};
class C:public A{
 
    public:
        void function(){
            cout<<"C::function"<<endl;
        }
 
};
//接收子类B传参

void fun(B b){
    b.function();
}
//接收子类C传参
void fun(C c){
    c.function();
}
int main(){
    B b;
    C c;
    fun(b);
    fun(c);
    return 0;
}

当一个基类有众多派生类时,如果使用隐藏来调用它们的某个同名函数,就需要考虑到所有派生类的类型作为参数,而对于覆写,只需要使用一个基类作为参数而传入派生类,通过c++的多态机制,就可以实现对派生类函数的调用。显然使用覆写是更好的选择

二、c++多态的实现

2.1 使用指针实现多态

程序:

#include<iostream>
using namespace std;
 
class fruit{
    public:
        virtual void get_price()=0;
};
class banana:public fruit{
    public:
        virtual void get_price(){
            cout<<"banana's price is 2$"<<endl;
        }
};
class apple:public fruit{
    public:
        virtual void get_price(){
            cout<<"apple's price is 3$"<<endl;
        }
};
class pineapple:public fruit{
    public:
        virtual void get_price(){
            cout<<"pineapple's price is 4$"<<endl;
        }
};
void price(fruit *f){
    f->get_price();
}
int main(){
    banana b;
    apple a;
    pineapple p;
    price(&b);
    price(&a);
    price(&p);
    return 0;
}

运行结果:

2.2 使用引用实现多态

程序:

#include<iostream>
using namespace std;
 
class fruit{
    public:
        virtual void get_price()=0;
};
class banana:public fruit{
    public:
        virtual void get_price(){
            cout<<"banana's price is 2$"<<endl;
        }
};
class apple:public fruit{
    public:
        virtual void get_price(){
            cout<<"apple's price is 3$"<<endl;
        }
};
class pineapple:public fruit{
    public:
        virtual void get_price(){
            cout<<"pineapple's price is 4$"<<endl;
        }
};
void price(fruit &f){
    f.get_price();
}
int main(){
    banana b;
    apple a;
    pineapple p;
    price(b);
    price(a);
    price(p);
    return 0;
}

运行结果:

2.3 总结

通过对多态特性的使用,可见多态功能的强大,只需调用基类的一个函数,可以实现派生类相关功能的调用,由此可以将基类虚函数设置为纯虚函数,实现接口的功能,便于派生类对其进行继承,覆写和扩展。