【问题标题】:How to override a virtual function with a non-virtual function?如何用非虚函数覆盖虚函数?
【发布时间】:2015-04-20 19:56:47
【问题描述】:

参考这个问题:Hide virtual function with non-virtual override

还有这个问题:override on non-virtual functions

覆盖虚函数的函数也是虚函数,即使它没有显式声明为虚函数。

我的技术问题是:是否可以使该覆盖函数成为非虚拟函数(并将其应用于层次结构中较低的类)?换句话说,我可以把“虚拟”关掉吗?

显然我们可以用虚函数覆盖一个非虚函数。我们可以做相反的事情,即用非虚函数覆盖虚函数吗?

【问题讨论】:

  • 恐怕您的问题与您链接的第一个问题重复。你能编辑你的问题来解释它是怎么回事吗?

标签: c++ inheritance overriding virtual


【解决方案1】:

C++ 引入了final。我没有使用它,但这是你的解决方案。该方法仍然是虚拟的,但不能被覆盖。

【讨论】:

  • 不是我的意思。我的意思是一个可以像我们覆盖非虚拟函数一样被覆盖的函数(并且不使用“覆盖”标识符)。还是您称其为“隐藏”而不是“压倒一切”?虽然这是一个技术问题,但我实际上并没有使用它的场景。
  • 不能关闭虚拟化,如果你是这个意思的话。
  • 我编写了一个示例,但后来发现它与 Paul Evans 已经提供的示例相同,只是我更喜欢 auto 语法。
【解决方案2】:

你想使用c++11 final,类似:

struct A {
    virtual void foo();
};

struct B : A {
    void foo() final;       // virtual overrides A::foo
};

struct C : B {
    void foo();             // error: can't override
};

【讨论】:

    【解决方案3】:

    您正在寻找一种方法来覆盖虚函数,使其不再是虚函数。

    使用继承的可能方法

    不幸的是,一旦成员函数被声明为虚拟,就无法摆脱它的虚拟性。这是 C++ 标准的直接结果:

    10.3/2:如果在 Base 类和 Derived 类中声明了虚成员函数 vf,则 直接或间接从 Base 派生, 同名的成员函数 vf , parameter-type-list , cv-qualification 和 refqualifier(或没有相同)作为 Base::vf 是 声明,则 Derived::vf 也是虚拟的

    使用final 不会解决您的问题:它只会禁止您在更多派生类中覆盖该函数。该功能将保持虚拟。

    然而,有一个(不方便的)技巧可以使用多重继承在一个特定级别删除虚拟化:

    class A {
    public:
        virtual void foo() { cout << "A" << endl; }
    };
    class B : public A {
    public:
        void foo() { cout << "B" << endl; }
    };
    class C : public B { 
    public:
        void foo() { cout << "C" << endl; }
    };
    class EH {   // Helper class, does not derive from A 
    public:      // so foo() is non virtual here
        void foo() {   cout << "EH!" << endl; }
    };
    class E : public B, public EH { // inherits the virtual foo and the non virtual one
    public:
        using EH::foo;     // We just say to use the non virtual one
    };
    

    类 E 继承自虚拟和非虚拟。我们只是说如果有人调用它就使用非虚拟的:

    E e; 
    e.foo();          // calls the non virtual function EH::foo(); => EH!
    B* pb2 = &e; 
    pb2->foo();       // calls the original virtual function B::foo() => B
    

    请注意,此技巧仅适用于当前级别:如果您从 E 派生一个类,该类也将间接继承自 A,这又是虚拟诅咒!

    你打算实现什么目标?

    使用虚函数,您可以确保始终调用与对象的真实身份相对应的适当函数,而不管您使用指向基址的指针这一事实。这就是多态性的目标。

    对于非虚拟函数,您的编译器会根据您访问的类型调用他认为正确的函数。如果您通过有效的基指针访问对象,它将因此使用基类的函数而不是派生的函数。这真的是你想要的吗?

    如果是,请这样做:

    C c;
    B* pb = &c;
    pb->foo();         // uses the virtual function
    pb->B::foo();      // but you can force to use the function, ignoring the virtuality.  
    

    使用虚函数和非虚函数的可能方法

    只需很少的额外成本,您就可以在代码中模拟这种行为,使用 2 个函数的组合:私有虚拟函数和公共非虚拟函数:

    class A {
        virtual void foo2() { cout << "A" << endl; }  // virtual function
    public:  
        void foo() { foo2(); } // non virtual function calling the virtual one 
    };
    class B : public A {
        void foo2() { cout << "B" << endl; }  // overriding virtual
    };
    class C : public B { 
    public:
        void foo() { cout << "C" << endl; }   // ignore the virtual and override the non virtual function :-) 
    };
    

    【讨论】:

      【解决方案4】:

      这是我的技术答案,不,如果我们不覆盖派生类中的虚函数,那么派生类的 vitable 将包含基类虚函数的地址。

      【讨论】:

        猜你喜欢
        • 2011-07-28
        • 2011-11-23
        • 1970-01-01
        • 2013-10-04
        • 2022-01-13
        • 2013-11-13
        • 1970-01-01
        • 2021-09-30
        • 2015-06-17
        相关资源
        最近更新 更多