zoukankan      html  css  js  c++  java
  • C++派生类中定义基类的虚函数时需注意的事项

      先给出文字说明,然后再给出代码解释:

      如果我们决定改写基类所提供的虚拟函数,那么派生类所提供的新定义,其函数型别必须完全符合基类所声明的函数原型,包括:参数列、返回型别、常量性(const-ness)

      下面给出程序说明:基类num_sequence中声明虚拟函数what_am_i(),派生类中改写该函数。

      1、正确的写法

      1.1 基类的声明

    1 #pragma once
    2
    3 class num_sequence
    4 {
    5 public:
    6 num_sequence(void);
    7 virtual const char* what_am_i() const { return "num_sequence \n"; } //注意这里的两个const
    8 virtual ~num_sequence(void);
    9 };

      1.2 派生类中正确的改写

    #pragma once
    #include "num_sequence.h"

    class Fibonacci :
    public num_sequence
    {
    public:
    Fibonacci(void);
    virtual const char* what_am_i() const { return "Fibonacci \n"; } //同样注意这里的两个const,少哪个都不行,
                                            //后面详解少其中任何一个const的运行情况
    ~Fibonacci(void);
    };


       上述是正确的改写,下面给出两种缺少const的错误改写:

    2.1 少 函数后面的const(即第二个const)

      Wrong1

     1 #pragma once
    2 #include "num_sequence.h"
    3
    4 class Fibonacci :
    5 public num_sequence
    6 {
    7 public:
    8 Fibonacci(void);
    9 virtual const char* what_am_i() { return "Fibonacci \n"; } //注意这里少了const
    10 ~Fibonacci(void);
    11 };

    main函数中测试:

     1 // EssentialCppP162.cpp : 定义控制台应用程序的入口点。
    2 //
    3
    4 #include "stdafx.h"
    5
    6 #include "Fibonacci.h"
    7 #include <iostream>
    8
    9 using namespace std;
    10 int _tmain(int argc, _TCHAR* argv[])
    11 {
    12 Fibonacci b;
    13 num_sequence p;
    14 num_sequence *pp = &b;
    15 cout << pp->what_am_i();
    16 cout << b.what_am_i();
    17 return 0;
    18 }

    输出的结果为:

    num_sequence
    Fibonacci
    请按任意键继续. . .

    解释:这里子类Fibonacci中并没有改写基类的what_am_i(),而是重新定义了一个what_am_i()函数(PS:这里说成是重载what_am_i()更合适)。所以尽管pp是指向子类的指针,但子类没有重定义该虚函数,最后就调用的是基类的what_am_i()函数,输出num_sequence。而b.what_am_i()则因为b为非const,会调用Fibonacci中的what_am_i())。(PPS:这里如果是const num_sequence *pp = &b; cout << pp->what_am_i(); 输出也是num_sequence,原因不说了。)

    PS:这里Essential C++ P161上说的是在 Intel C++编译器上编译时,会输出警告: warning #653: "const char *Fibonacci::what_am_i()" does not match "num_sequence::what_am_i" -- virtual function override intended?

      但我在VS200中文版中测试时候完全没有警告,所以写改写基类虚拟函数时候一定要小心,尽量用ctrl+c从基类中复制过来,防止手动敲入函数名字时出错。

    2.2 少函数返回类型中的的const(即前面的那个const)

      Wrong2

     1 #pragma once
    2 #include "num_sequence.h"
    3
    4 class Fibonacci :
    5 public num_sequence
    6 {
    7 public:
    8 Fibonacci(void);
    9 virtual char* what_am_i() const { return "Fibonacci \n"; }
    10 ~Fibonacci(void);
    11 };


      此种情况编译器不会通过编译,因为函数重载不是根据返回类型来定的,所以编译器会认为这里的what_am_i()是继承的基类的函数。然后根据本篇文章开头说的函数型别必须完全符合基类的声明,这里就会报错。VS2008下报错为:

      1>e:\vsprog\临时测试文件夹\essentialcppp162\essentialcppp162\fibonacci.h(11) : error C2555: “Fibonacci::what_am_i”: 重写虚函数返回类型有差异,且不是来自“num_sequence::what_am_i”的协变
      1>e:\vsprog\临时测试文件夹\essentialcppp162\essentialcppp162\num_sequence.h(7) : 参见“num_sequence::what_am_i”的声明

    2.3 两个const都少了

      Wrong3

     1 #pragma once
    2 #include "num_sequence.h"
    3
    4 class Fibonacci :
    5 public num_sequence
    6 {
    7 public:
    8 Fibonacci(void);
    9 virtual char* what_am_i() { return "Fibonacci \n"; }
    10 ~Fibonacci(void);
    11 };

    这和第一种错误一样,都是一个重载的函数,而不是改写基类的虚拟函数。。

    关于继承基类的虚拟函数的说明就到此结束。最后说一下改写基类的虚拟函数时,子类中声明不一定非得加上关键词virtual。编译器会依据两个函数的原型声明,决定某个函数是否会改写其基类中的同名函数( 比如这里1.2中可以写成这样const char* what_am_i() const { return "Fibonacci \n"; } )。

    =============================

    补充:

      “返回型别必须完全吻合” 这一规则有个例外:当基类的虚拟函数返回某个基类形式(通常是pointer或reference)时:派生类中的同名函数便可以返回该基类所派生出来的型别:举例如下(尚不知道这里实际工程项目中的用处):

    基类num_sequnece: virtual num_sequence *clone() = 0;

    子类Fibonacci: [virtual] Fibonacci *clone() { return new Fibonacci ( *this ); }




     

  • 相关阅读:
    算法竞赛入门经典习题2-3 韩信点兵
    ios入门之c语言篇——基本函数——5——素数判断
    ios入门之c语言篇——基本函数——4——数值交换函数
    144. Binary Tree Preorder Traversal
    143. Reorder List
    142. Linked List Cycle II
    139. Word Break
    138. Copy List with Random Pointer
    137. Single Number II
    135. Candy
  • 原文地址:https://www.cnblogs.com/ziyoudefeng/p/2407659.html
Copyright © 2011-2022 走看看