简体   繁体   English

C ++中的函数重写

[英]function overriding in c++

could anyone explain function overriding in c++ please! 谁能解释c ++中的函数重写! also am confused about virtual function concept. 也对虚拟功能概念感到困惑。 some tutorials say without the keyword virtual, both the derived class and base class objects invoke the base class function. 一些教程说,如果没有关键字virtual,则派生类和基类对象都将调用基类函数。 then how does overriding take place? 那么如何进行覆盖?

There's no need to redocument what is already good and out there. 无需重新记录已经存在的好东西。 I think this and this are a wonderful explanations about virtual functions. 我觉得是有关虚拟功能的精彩讲解。 Then you probably also need to hear about abstract classes. 然后,您可能还需要了解抽象类。 Let us know if you have further questions. 如果您还有其他问题,请告诉我们。

Read this please. 请阅读 Concentrate on C++ sections. 专注于C ++部分。 Then ask specific questions you have after reading. 阅读完后,再问一些具体问题。

Let me try to post an example (This is out of my head, so there may be slight syntax errors :) ) 让我尝试发布一个示例(这超出了我的理解,因此可能会有轻微的语法错误:))

Baseclass: 基类:

class BaseClass
{
public:
   void normalFunction();
   virtual void virtualFunction();
}

Derived class: 派生类:

class DerivedClass : public BaseClass
{
public:
   void normalFunction();
   virtual void virtualFunction();
}

Okay, so we got our classes defined. 好的,所以我们定义了类。 Now, some examples: 现在,举一些例子:

void main()
{
    BaseClass base;
    DerivedClass derived;

    base.normalFunction();   //Invokes BaseClass::normalFunction();
    base.virtualFunction();  //Invoked BaseClass::virtualFunction();

    derived.normalFunction();//Invokes DerivedClass::normalFunction();
    derived.virtualFunction();//Invokes DerivedClass::virtualFunction();

    // Okay, nothing special yet, here comes the fun:
    BaseClass *basePtr = &base;
    BaseClass *derivedPtr = &derived;

    basePtr->normalFunction(); //Invokes BaseClass::normalFunction();
    basePtr->virtualFunction();//Invokes BaseClass::virtualFunction();

    derivedPtr->normalFunction(); //Invokes BaseClass::normalFunction(); !! this is because it's a BaseClass pointer.
    derivedPtr->virtualFunction();//Invokes DerivedClass::virtualFunction();
}

.. So, in conclusion, without virtual, the type of the pointer dictates which method will be invoked, with virtual, any type overriding the virtual method will have it's method called regardless of the pointer type :) ..因此,总而言之,在没有虚拟的情况下,指针的类型决定了将调用哪个方法,在使用虚拟的情况下,任何覆盖虚拟方法的类型都将调用该方法,而与指针的类型无关:)

This is at a cose of a very minor overhead in the form of a vtable (virtual table), a compiler-detail which will map each method to the different derived types. 以vtable(虚拟表)的形式进行的工作非常少,这是编译器详细信息,它将每个方法映射到不同的派生类型。

Each C++ class that has at least one virtual function contains a "virtual table" or VTABLE which is used to dynamically look up the address of a function at runtime. 每个具有至少一个虚函数的C ++类都包含一个“虚表”或VTABLE,用于在运行时动态查找函数的地址。

Suppose you have two classes: Base and Derived. 假设您有两个类:基本类和派生类。 Further suppose that Derived derives from Base, and that "b" and "d" are instances of Derived, but b's compile-time type is Base and d's is Derived. 进一步假设Derived是从Base派生的,而“ b”和“ d”是Derived的实例,但是b的编译时类型是Base,而d的是编译时类型。

Now suppose that both Base and Derived declare a function "foo". 现在假设Base和Derived都声明一个函数“ foo”。 Now, if "foo" is declared to be virtual in Base, then "foo" will have an entry in Base's VTABLE, and when you call "b.foo()" or "d.foo()", the compiler will know that it is a virtual function, and it will inject code that will look up the address of "foo" in the VTABLE at runtime.... which will find the address of the definition of "foo" as given in class Derived (ie Derived::foo). 现在,如果“ foo”在Base中声明为虚拟的,则“ foo”将在Base的VTABLE中具有一个条目,并且当您调用“ b.foo()”或“ d.foo()”时,编译器将知道它是一个虚函数,它将在运行时注入将在VTABLE中查找“ foo”的地址的代码。。。它将找到类Derived中给出的“ foo”定义的地址(即派生:: FOO)。

Now suppose that both Base and Derived declare a function "foo", but "foo" has not been declared virtual in Base. 现在假设Base和Derived都声明了一个函数“ foo”,但是在Base中尚未将“ foo”声明为虚函数。 When you call "b.foo()" or "d."foo()" the compiler will attempt to call Base::foo and Derived::foo directly, bypassing the virtual table lookup. Even though b's runtime type may be Derived, b's compile-time type is Base, and so calling "b.foo()" will result in "Base::foo" rather than "Derived::foo" being called. 当您调用“ b.foo()”或“ d。” foo()“时,编译器将尝试直接调用Base :: foo和Derived :: foo,绕过虚拟表查找,即使b的运行时类型可能是派生的,b的编译时类型为Base,因此调用“ b.foo()”将导致调用“ Base :: foo”,而不是被调用“ Derived :: foo”。

In C++, the term "overriding" is used to refer to the former case; 在C ++中,术语“覆盖”用于表示前一种情况。 that is, when the function is declared as virtual, and another function in a derived class replaces the original function that was defined in the base class. 也就是说,当函数被声明为虚拟函数时,派生类中的另一个函数将替换基类中定义的原始函数。 By contrast, the term "overshadowing" is used to refer to the latter case; 相反,术语“遮盖”是指后一种情况。 that is, a function in the derived class is called instead of the one in the base class, simply because it is closer in scope, but it has not truly replaced the function that was defined in the base class. 就是说,派生类中的一个函数而不是基类中的一个函数被调用,只是因为它的作用域更近,但是它并没有真正替代基类中定义的函数。

The override can only be done if you declare the function in the super virtual. 仅当您在超级虚拟环境中声明该函数时,才能进行覆盖。 Because it is virtual so it's not true ... meaning that is someone invoke it with that signature it may not invoke that function. 因为它是虚拟的,所以它不是真的... ...意味着有人用该签名调用它,因此它可能不会调用该函数。 We have to wait and see at runtime if someone overridden it. 我们必须等待并在运行时查看是否有人重写了它。 That is the meaning of virtual. 那就是虚拟的含义。

class A {
            void F_A() { cout << "A' A"; }
    virtual void F_B() { cout << "A' B"; }
}
class B : public A {
    void F_B() { cout << "B' B"; }
}

A o = new B();
o.F_A();  // Non-virtual so the compiler knows that it can only be the one in class A
o.F_B();  // Virtual so the compiler does not know if at runtime ... o is instance of A or B. So it have to wait and see.
// In this case, it's B at runtime ('`new B()`'), so it run the one in B.

To sum up, if a function (method to be more precise) is declared ' virtual' , it can be overridden. 综上所述,如果某个函数(更精确的方法)被声明为“ virtual' ,则可以将其覆盖。 Otherwise, it can't be; 否则,它不会; hence, any invocation always goes to the one in the super class. 因此,任何调用始终归超级类所有。

Hope this help clarifying. 希望这有助于澄清。

For Virtual function always remember this thumb rule : 对于虚拟函数,请始终记住以下经验法则:

  • When function is normal then function of type of object will be invoked, 当函数正常时,将调用对象类型的函数,
  • When function is Virtual then function of type of actual instance will be called. 当函数为Virtual时,将调用实际实例类型的函数。

I like to illustrate this example with a Chess board; 我想用一个国际象棋棋盘来说明这个例子。

class ChessPiece
{
    public:
        void moveTo(Pos dst);
        virtual checkValidAndMoveTo(Pos dst) = 0;
};
class King: public ChessPieve
{        virtual checkValidAndMoveTo(Pos dst);}
class Queen: public ChessPieve
{        virtual checkValidAndMoveTo(Pos dst);}
// etc

ChessPiece*   board[8][8];

So when a move is made to square the game will call checkValidAndMoveTo() on the piece. 因此,当进行平方移动时,游戏将在棋子上调用checkValidAndMoveTo()。

board[pickedUpPiece.x][pickedUpPiece.y]->checkValidAndMoveTo()

This will now call the appropriate checkValidAndMoveTo() for the particular piece. 现在,将为特定片段调用适当的checkValidAndMoveTo()。 Once this move is finished we expect it to call MoveTo(). 一旦移动完成,我们希望它调用MoveTo()。 Since at the point it knows what type is is it will drill to down and get the most overidden version of MoveTo() below it current type. 由于此时它知道什么是类型,因此它将向下钻取并获得当前类型下方最易移动的MoveTo()版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM