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++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

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++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域