【问题标题】:c++ non virtual function acts like virtual function [duplicate]c ++非虚函数的作用类似于虚函数[重复]
【发布时间】:2021-01-26 12:05:17
【问题描述】:

可能,我误解了 C++ 多态性(虚函数)。 请指出我想念的东西。

源码如下


#include <iostream>

using namespace std;

class A {
    public:
        virtual void print(void) {
            cout<<"class A"<<endl;
        }
};

class B : public A {
    public:
        void print(void) {
            cout<<"class B"<<endl;
        }
};

class C : public B {
    public:
        void print(void) {
            cout<<"class C"<<endl;
        }
};

int main() {
    A a;
    B b;
    C c;
    A *pAa = &a;
    A *pAb = &b;
    A *pAc = &c;
    B *pBc = &c;

    pAa->print();
    pAb->print();
    pAc->print();
    pBc->print();                   // shouldn't be "class B"

    return 0;
}

result

------------------------------
class A
class B
class C
class C                             // shouldn't be "class B"

我的理解是 最后一个打印语句应打印“B 类” 因为 pBc 是 B 类的指针,而 B 类中的 print 函数是非虚成员函数。我找不到关于这种情况的答案。

请告诉我原因或指出我在哪里可以找到答案并 理解 C++ 的多态性。 谢谢。

【问题讨论】:

  • 看来你从答案中得到了帮助,然后你可以accept 其中一个。

标签: c++ polymorphism virtual


【解决方案1】:

B类中的打印函数是非虚成员函数

没有。由于A::print被标记为virtual,而B继承自A,那么B::print也是virtual;不管上面是否指定了 virtual 键。

(强调我的)

如果某个成员函数 vf 在类 Base 中被声明为 virtual,并且 一些派生类,直接或间接派生自 Base, 有一个相同的成员函数声明

  • 姓名
  • 参数类型列表(但不是返回类型)
  • cv 限定符
  • 引用限定符

那么 Derived 类中的这个函数也是虚拟的(在它的声明中是否使用了关键字 virtual)并覆盖了 Base::vf(无论是否在它的声明)。

【讨论】:

  • 一次虚拟,永远虚拟。我总是在派生类中留下关键字作为提醒。特别是在深层继承树中。
  • @DuncanACoulter 一个更好的选择 (imo) 是在派生类中使用 override,因为如果它实际上是 not 覆盖时它会给你一个错误目的。使用 virtual 只有当您打算覆盖时,您才可以引入新的重载。
  • 现在我清楚地明白我想念什么了。谢谢。
  • @TedLyngmo 是的一个好点
【解决方案2】:

如果具有给定签名的函数在顶级基类中被声明为虚函数,那么该函数在所有派生类中都是虚函数无论是否使用关键字virtual 标记(override, final) 与否:

virtual function specifier

那么Derived类中的这个函数也是虚的(无论在其声明中是否使用了关键字virtual

struct Base {
    // Pure virtual function.
    virtual void foo() const = 0;  
};

struct A : public Base {
    // Overriding virtual function, even if it 
    // is not marked as virtual (override, or final).
    void foo() const {}   
};

A 中,将virtual 说明符添加到foo() 只会带来语义 值; virtual 是否省略在功能上没有区别(除非有人更改了Base 中的接口)。


许多静态分析器强制(1)使用overridefinal 标记派生虚函数,原因有两个:

  • 语义;清楚地表明给定函数是一个虚函数(根据在继承链中的更高层定义),并且
  • 执行;如果一个函数被标记为overridefinal 但实际上不是一个覆盖函数,你会得到一个编译器错误,这对于在更改基类接口时防止错误特别有用(虽然忘记了哪些类实际实现了这个接口)。

例如:

struct Base {
    // Pure virtual function.
    virtual void foo() const = 0;  
};

struct A : public Base {
    // Overriding virtual function.
    void foo() const override {}   
};

struct B final : public Base {
    // Overriding (final) virtual function.
    void foo() const final {}

    // Error: Function does not override.
    // void bar() const override {}
};

(1) 例如Autsar C++14 Language Guidelines(汽车安全关键开发)中的规则 A10-3-1 被归类为必需规则虚拟函数声明应包含三个说明符之一:(1 ) virtual, (2) override, (3) final.

【讨论】:

  • 现在我清楚地明白我想念什么了。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-06
  • 2013-07-30
  • 1970-01-01
  • 2012-08-27
  • 2011-09-16
  • 1970-01-01
相关资源
最近更新 更多