简体   繁体   中英

How virtual and non-virtual functions are called

using namespace std;

class Foo
{
    public:
        virtual void foo();
        void foo2();
};
class Bar : public Foo
{
    public:
        void foo();
        void foo2();
};
int main()
{
    Foo* f = new Foo;
    f->foo();         **//1**
    f->foo2();       **//2**
    return 0;
}

How compiler knows, 1) is dynamic in nature and 2) is static. How both are internally called.

Collected from here . . .

Non-virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object.

In contrast, virtual member functions are resolved dynamically (at run-time). That is, the member function is selected dynamically (at run-time) based on the type of the object, not the type of the pointer/reference to that object. This is called “dynamic binding.” Most compilers use some variant of the following technique: if the object has one or more virtual functions, the compiler puts a hidden pointer in the object called a “virtual-pointer” or “v-pointer.” This v-pointer points to a global table called the “virtual-table” or “v-table.”

A pure virtual function is a function that must be overridden in a derived class and need not be defined. A virtual function is declared to be “pure” using the curious =0 syntax. For example:

class Base {
public:
    void f1();      // not virtual
    virtual void f2();  // virtual, not pure
    virtual void f3() = 0;  // pure virtual
};
Base b; // error: pure virtual f3 not overridden

Here, Base is an abstract class (because it has a pure virtual function), so no objects of class Base can be directly created: Base is (explicitly) meant to be a base class. For example:

class Derived : public Base {
    // no f1: fine
    // no f2: fine, we inherit Base::f2
    void f3();
};
Derived d;  // ok: Derived::f3 overrides Base::f3

Example for Virtual or non-Virtual Fenction

#include <iostream>
using namespace std;

class Base {
    public:
          virtual void NameOf();   // Virtual function.
          void InvokingClass();   //  Nonvirtual function.
          };

// Implement the two functions.
void Base::NameOf() {
    cout << "Base::NameOf\n";
   }

void Base::InvokingClass() {
    cout << "Invoked by Base\n";
   }

class Derived : public Base {
    public:
          void NameOf();   // *Virtual function*.
          void InvokingClass();   // *Nonvirtual function.*
  };

// Implement the two functions.
void Derived::NameOf() {
    cout << "Derived::NameOf\n";
 }

void Derived::InvokingClass() {
   cout << "Invoked by Derived\n";
 }

Main

int main() {
   // Declare an object of type Derived.
      Derived aDerived;

   // Declare two pointers, one of type Derived * and the other
   //  of type Base *, and initialize them to point to aDerived.
      Derived *pDerived = &aDerived;
      Base    *pBase    = &aDerived;

  // Call the functions.
     pBase->NameOf();           // Call virtual function.
     pBase->InvokingClass();    // Call nonvirtual function.
     pDerived->NameOf();        // Call virtual function.
     pDerived->InvokingClass(); // Call nonvirtual function.
}

In your example both foo() and foo2() will be from the Foo class.

int main()
{
    Foo* f = new Foo;
    f->foo();                        // Foo::foo
    f->foo2();                       // Foo::foo2
    return 0;
}

For you to illustrate the virtual behavior, you need to make an instance of the derived class

int main()
{
    Foo* b = new Bar;
    b->foo();                        // Bar::foo
    b->foo2();                       // Foo::foo2
    static_cast<Bar*>(b)->foo2();    // Bar::foo2
    return 0;
}

Notice in the latter case, since b is actually a Bar , it invokes the overriden virtual method foo . But since foo2 isn't declared virtual and b is a Foo , it will invoke Foo::foo2 . However, if we cast f to a Bar , it will invoke Bar::foo2

virtual keyword tells compiler for dynamic binding.

To view dynamic binding in action instantiate Foo pointer with Bar object , refer below code.

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

class Foo
{
    public:
        virtual void foo(){std::cout<<"Foo foo"<<std::endl;};
        void foo2(){std::cout<<"Foo foo2"<<std::endl;};
};
class Bar : public Foo
{
    public:
        void foo(){std::cout<<"Bar foo"<<std::endl;};
        void foo2(){std::cout<<"Bar foo2"<<std::endl;};
};
int main()
{
    Foo* f = new Bar;
    f->foo();
    f->foo2();
    return 0;
}

A class which declares or inherits virtual functions has something called a vtable which is used to look up which function to call when you invoke a virtual function. In effect, this table contains pointers to all the virtual functions in the class, something like this (pseudo-code - this may or may not compile):

class Foo {
    void foo_impl(){std::cout<<"Foo foo"<<std::endl;}
    struct {
        void (*foo_ptr)();
    } vtable;
    public:
        Foo(){vtable.foo_ptr = &Foo::foo_impl;}
        void foo(){vtable.foo_ptr();}
        void foo2(){std::cout<<"Foo foo2"<<std::endl;}
};
class Bar : public Foo {
    void foo_impl(){std::cout<<"Bar foo"<<std::endl;}
    public:
        Bar(){vtable.foo_ptr = &Bar::foo_impl;}
        void foo2(){std::cout<<"Bar foo2"<<std::endl;}
};

Thus, when you call a virtual function, the address is first looked up in the vtable , so if you assign a Bar bar; Foo& foo = bar; Bar bar; Foo& foo = bar; , then foo.foo() calls Bar 's version of foo() instead of Foo 's version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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