C++中的overload,overwritting,overriding

2024-04-27 05:08

本文主要是介绍C++中的overload,overwritting,overriding,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

“overload”翻译过来就是:超载,过载,重载,超出标准负荷;“override”翻译过来是:重置,覆盖,使原来的失去效果。 


先来说说重载的含义,在日常生活中我们经常要清洗一些东西,比如洗车、洗衣服。尽管我们说话的时候并没有明确地说用洗车的方式来洗车,或者用洗衣服的方式来洗一件衣服,但是谁也不会用洗衣服的方式来洗一辆车,否则等洗完时车早就散架了。我们并不要那么明确地指出来就心知肚明,这就有重载的意思了。在同一可访问区内被声名的几个具有不同参数列的(参数的类型、个数、顺序不同)同名函数,程序会根据不同的参数列来确定具体调用哪个函数,这种机制叫重载,重载不关心函数的返回值类型。这里,“重载”的“重”的意思不同于“轻重”的“重”,它是“重复”、“重叠”的意思。例如在同一可访问区内有: 


① double calculate(double); 


② double calculate(double,double); 


③ double calculate(double, int); 


④ double calculate(int, double); 


⑤ double calculate(int); 


⑥ float calculate(float); 


⑦ float calculate(double); 


六个同名函数calculate,①②③④⑤⑥中任两个均构成重载,⑥和⑦也能构成重载,而①和⑦却不能构成重载,因为①和⑦的参数相同。 


覆盖是指派生类中存在重新定义的函数,其函数名、参数列、返回值类型必须同父类中的相对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体(花括号中的部分)不同,当派生类对象调用子类中该同名函数时会自动调用子类中的覆盖版本,而不是父类中的被覆盖函数版本,这种机制就叫做覆盖。 


下面我们从成员函数的角度来讲述重载和覆盖的区别。 


成员函数被重载的特征有: 


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


2) 函数名字相同; 


3) 参数不同; 


4) virtual关键字可有可无。 


覆盖的特征有: 


1) 不同的范围(分别位于派生类与基类); 


2) 函数名字相同; 


3) 参数相同; 


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


比如,在下面的程序中: 


#include <iostream.h> 


class Base 





public: 


void f(int x){ cout << "Base::f(int) " << x << endl; } 


void f(float x){ cout << "Base::f(float) " << x << endl; } 


virtual void g(void){ cout << "Base::g(void)" << endl;} 


}; 


class Derived : public Base 





public: 


virtual void g(void){ cout << "Derived::g(void)" << endl;} 


}; 


void main(void) 





Derived d; 


Base *pb = &d; 


pb->f(42); // 运行结果: Base::f(int) 42 


pb->f(3.14f); // 运行结果: Base::f(float) 3.14 


pb->g(); // 运行结果: Derived::g(void) 





函数Base::f(int)与Base::f(float)相互重载,而Base::g(void)被Derived::g(void)覆盖。 


隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下: 


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


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


比如,在下面的程序中: 


#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; } 


}; 


通过分析可得: 


1) 函数Derived::f(float)覆盖了Base::f(float)。 


2) 函数Derived::g(int)隐藏了Base::g(float),注意,不是重载。 


3) 函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。 


看完前面的示例,可能大家还没明白隐藏与覆盖到底有什么区别,因为我们前面都是讲的表面现象,怎样的实现方式,属于什么情况。下面我们就要分析覆盖与隐藏在应用中到底有什么不同之处。在下面的程序中bp和dp指向同一地址,按理说运行结果应该是相同的,可事实并非如此。 


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 


// Bad : behavior depends on type of the pointer 


pb->h(3.14f); //运行结果: Base::h(float) 3.14 


pd->h(3.14f); //运行结果: Derived::h(float) 3.14 





请大家注意,f()函数属于覆盖,而g()与h()属于隐藏。从上面的运行结果,我们可以注意到在覆盖中,用基类指针和派生类指针调用函数f()时,系统都是执行的派生类函数f(),而非基类的f(),这样实际上就是完成的“接口”功能。而在隐藏方式中,用基类指针和派生类指针调用函数f()时,系统会进行区分,基类指针调用时,系统执行基类的f(),而派生类指针调用时,系统“隐藏”了基类的f(),执行派生类的f(),这也就是“隐藏”的由来。

这篇关于C++中的overload,overwritting,overriding的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/939591

相关文章

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

Java 方法重载Overload常见误区及注意事项

《Java方法重载Overload常见误区及注意事项》Java方法重载允许同一类中同名方法通过参数类型、数量、顺序差异实现功能扩展,提升代码灵活性,核心条件为参数列表不同,不涉及返回类型、访问修饰符... 目录Java 方法重载(Overload)详解一、方法重载的核心条件二、构成方法重载的具体情况三、不构

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat