[C++再学习系列] 派生类函数的重实现规则(override-覆盖)

简介:

  对于用过C++的人大体都清楚:派生类可以重实现基类中声明为virtual的函数,并且很清楚如果想实现正确的重写,必须满足:派生类重实现的函数的所有属性和基类virtual函数一致,即函数签名,const限制均一样。同时为了更好地传达代码意图,重实现的virtual函数最好添加冗余的virtual关键字。

  上面这些是基本要求,对于重实现,还有3个需要注意的地方:

  1) 保证可替换性: 任何派生类都必须遵守基类所承诺的前条件和后条件。当然改写后函数可以要求更少保证更多,反之不行。

  2) 永远不要修改默认参数。切记:默认参数并非函数签名的组成部分,修改重实现函数的默认参数,并不会导致重实现失败,但会导致糟糕的默认参数错误。对于调用者而言,同一个对象的成员函数会不加提示地根据自己访问所使用的静态类型而接受不同的参数。换句话说,重实现函数的默认参数并不具有多态属性。

  3)  谨防基类重载(overload)函数被重实现函数所隐藏(overwrite)。(这和C++的名字查找相关)

示例1:默认参数问题

class Base {

  virtual void Foo( int x = 0 );

};

class Derived : public Base {

  virtual void Foo( int x = 1 );       // poor form, and surprise-inducing

};

Derived *pD = new Derived;

pD->Foo();                       // invokes pD->Foo(1)

Base *pB = pD;

pB->Foo();                       // invokes pB->Foo(0)

示例:隐藏基类重载函数

class Base{

  virtual void Foo( int );

  virtual void Foo( int, int );

  voidFoo( int, int, int );

};

class Derived : public Base {

  virtual void Foo( int );     // overrides Base::Foo(int), but hides theothers

};

Derived d;

d.Foo( 1 );                 // ok

d.Foo( 1, 2 );             // error (oops?)

d.Foo( 1, 2, 3 );         // error (oops?)

  问题产生的原因:C++编译器的编译过程分3步:名字查找,重载解析和访问性检查。为加快名字查找速度,编译器是逐步扩大名字查找范围的。以上述例子为例:d.Foo( 1, 2 ); 在名字查找时,编译器首先发现派生类存在Foo函数,并停止名字查找;接着进行函数的重载解析,并发现派生类中,并未找到合适函数签名的Foo函数,报错!

  解决方案:使用using引入基类的特定名字(见<Using声明和指令的工作原理>)。

class Derived : public Base {// …

  virtual void Foo( int );      // overrides Base::Foo(int)

  using Base::Foo;              // bring the other Base::Foooverloads into scope

};

相关文章:

揭秘:C++编译器的函数编译流程

[C++再学习系列] Using声明和指令的工作原理

---------------------------------------------------

兄弟的公司:立即购--手机购物,诚信网购

欢迎转载,请注明作者和出处。

本文转自 zhenjing 博客园博客,原文链接:http://www.cnblogs.com/zhenjing/archive/2010/12/02/override_overwrite_overload.html   ,如需转载请自行联系原作者


相关文章
|
14天前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
19天前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
30天前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
43 6
|
30天前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
21 0
C++ 多线程之线程管理函数
|
1月前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
130 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
38 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
22天前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
21 4
|
22天前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
20 4
|
22天前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
17 1
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)