05. Virtual Function
HomeDesign PatternC++

05. Virtual Function

how to handle virtual function with cast

07. Prototype Pattern
06. LSP
04. Adapter

DesignPattern

Usages

  • Override a function of a parent class

Explain

Dynamic Binding with Virtual Keyword

C++ is a compile based language. A compile is a job to translate source code to binary for machine. When compiler compiles source code, it tries to optimize source code to improve performance. This is the one of reasons why C/C++ is faster than other programming language.

However, compile is a static job. Because a compiler could not know what happens in a run time, it only relies on source code. A pointer for derived class object is a good example. If a pointer is declared for base class but it refers to derived class object, compiler just links it to base class's member.

However, sometimes, something should work in run time. If a programmer wants to use a base class pointer to indicate an actual object, not only for base class object, virtual keyword is necessary. Virtual tells a compiler that the target object of the member is determined in run time. Therefore, a compiler does not link the pointer to a class object statically.

Virtual is very useful for overriding. Overriding is the situation that derived classes have members whose name is the same as base class', but its mechanism is little different. In that case, a pointer for base class is a handler for base and derived classes both. With virtual keyword, the target object is determined in run time.

Code 1 shows a simple example of virtual.

// 01_C_VirtualFunction.cpp
#include <iostream>
using namespace std;

class BaseClass
{
public:
    void foo()
    {
        cout << "BaseClass foo" << endl;
    }

    virtual void var()
    {
        cout << "BaseClass var" << endl;
    }
};

class DerivedClass : public BaseClass
{
public:
    void foo()
    {
        cout << "DerivedClass foo" << endl;
    }

    virtual void var()
    {
        cout << "DerivedClass var" << endl;
    }
};

int main()
{
    BaseClass b;
    DerivedClass d;
    BaseClass* p = &d;

    b.foo();        // BaseClass foo
    d.foo();        // DerivedClass foo
    p->foo();       // BaseClass foo

    b.var();        // BaseClass var
    d.var();        // DerivedClass var
    p->var();       // DerivedClass var

    return 0;
}
// Compile: clang++ -std=c++14
//              -o 01_C_VirtualFunction 01_C_VirtualFunction.cpp
C++
Code 1. Virtual
BaseClass foo
DerivedClass foo
BaseClass foo
BaseClass var
DerivedClass var
DerivedClass var

In this example, The type of pointer p is BaseClass, but it refers to an object of DerivedClass. Because run() is a member function without virtual keyword, p->run() indicates run() of base class, BaseClass. However, eat() is with virtual. Therefore, when eat() is called, DerivedClass's eat() is executed, because the target of p is the object of DerivedClass.

Virtual Function Table

When at least one member function is with virtual keyword, a virtual function table is created for its class, and additional pointer variable is located in the class. Code 2 checks the size of class whose one of member functions is with virtual keyword.

// 02_C_VirtualSize.cpp
#include <iostream>
using namespace std;

class BaseClass
{
protected:
    int val;

public:
    BaseClass(int _val)
        : val(_val)
    {}

    virtual void setVal(int _val)
    {
        val = _val;
    }

    virtual int getVal()
    {
        return val;
    }

    virtual void print()
    {
        cout << "BaseClass val: " << val << endl;
    }
};

class DerivedClass : public BaseClass
{
protected:
    int num;

public:
    DerivedClass(int _val, int _num)
        : BaseClass(_val)
        , num(_num)
    {}

    void setNum(int _num)
    {
        num = _num;
    }

    virtual void print()
    {
        cout << "DerivedClass val: " << val
             << ", num: " << num << endl;
    }
};

int main()
{
    BaseClass b(1);
    cout << sizeof(b) << endl;  // 16
                                // = 4 (for int val)
                                // + 4 (for alignment)
                                // + 8 (for the pointer
                                //      for virtual function table)

    DerivedClass d(2, 3);
    cout << sizeof(d) << endl;  // 16
                                // = 4 (for int val)
                                // + 4 (for num)
                                // + 8 (for the pointer
                                //      for virtual function table)

    BaseClass* p = &d;
    cout << sizeof(p) << endl;  // 8 (size of pointer)

    return 0;
}
// Compile: clang++ -std=c++14
//              -o 02_C_VirtualSize 02_C_VirtualSize.cpp
C++
Code 2. Size of virtual function table
16
16
8

The additional 8 byte is from the pointer for virtual function table. Image 1 shows how their memories are.

Image 1. Memory for inheritance

If base class's virtual function is overrided, the target of virtual function table's element indicates the function of derived class. If not overrided, functions for base class are used. In this example, only print() is an override function. Therefore, the third element of virtual function table of DerivedClass indicates DerivedClass::print(). If a new function is defined without virtual keyword, it is not registered on virtual function table, like setNum().

Dynamic Cast for Virtual Function

C++ provides 4 types of cast, and they have different features. One of the representative differences is how to handle virtual functions in downcasting. Downcasting is to cast a pointer for a base class to a pointer for a derived class.

Static cast and reinterpret cast casts a pointer for a source class to a target class in the compile time. At that time, compiler does not know a an actual type of an object, but only a type of the target class. Therefore, the compiler does not change the pointer of virtual function table. Because, however, Non-virtual functions are determined by the type of the pointer, derived class' non-virtual functions are used.

On the other hands, dynamic_cast checks the real type of the object in the run time, so the pointer for virtual function table can be changed. After casting, it refers to the pointer of virtual function table for the target class.

Code 3 shows how they work for downcasting.

// 03_C_DynamicVirtual.cpp
#include <iostream>
using namespace std;

class BaseClass
{
public:
    void foo()
    {
        cout << "BaseClass foo" << endl;
    }

    virtual void var()
    {
        cout << "BaseClass var" << endl;
    }
};

class DerivedClass : public BaseClass
{
public:
    void foo()
    {
        cout << "DerivedClass foo" << endl;
    }

    virtual void var()
    {
        cout << "DerivedClass var" << endl;
    }
};

int main()
{
    BaseClass b;
    DerivedClass* p = reinterpret_cast(&b);

    p->foo();           // DerivedClass foo
    p->var();           // BaseClass var

    p = static_cast(&b);

    p->foo();           // DerivedClass foo
    p->var();           // BaseClass var

    p = dynamic_cast(&b);

    if (p == nullptr)
    {
        cout << "Dynamic_cast failed" << endl;
        p->foo();    // DerivedClass foo
        p->var();    // Segmentation fault
    }

    return 0;
}
// Compile: clang++ -std=c++14
//              -o 03_C_DynamicVirtual 03_C_DynamicVirtual.cpp
C++
Code 3. Cast with/without virtual
DerivedClass foo
BaseClass var
DerivedClass foo
BaseClass var
Dynamic_cast failed
DerivedClass foo
Segmentation fault

However, dynamic_cast is not usually used for downcasting, because it can be failed when the type of the pointer and the type of the object are not compatible. If dynamic_cast is failed, it returns nullptr. As a result, a program crashes with segmentation fault at a virtual function.

Reinterpret Cast for Virtual Function

Reinterpret cast is a very powerful cast. It can do any type change. However, it is done in compile time, so it does not change the pointer for virtual function table. Code 4 shows how it works.

// 04_C_ReinterpretVirtual.cpp
#include <iostream>
using namespace std;

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

class B
{
public:
    virtual void var()
    {
        cout << "B var" << endl;
    }

    virtual void set()
    {
        cout << "A set" << endl;
    }
};

int main()
{
    A a;
    B* p = reinterpret_cast(&a);

    p->var();       // A foo
    p->set();       // Segmentation fault

    return 0;
}
// Compile: clang++ -std=c++14
//              -o 04_C_ReinterpretVirtual 04_C_ReinterpretVirtual.cpp
C++
Code 4. Reinterpret cast
A foo

By reinterpret_cast, the type is changed, but the pointer for virtual function table is not changed. Because virtual functions in virtual function table are stored with indexes, B's var() calls A's foo(). However, A has only one virtual function, foo(), so B's set() raises the segmentation fault. Image 2 shows how their memories are.

Image 2. Memory for reinterpret cast

Summary

  • Virtual keyword allows dynamic binding(Run Time Binding)
  • Virtual creates a virtual function table and its pointer, so the memory size is increased.
  • When dynamic_cast is failed, virtual functions leads a segmentation fault.
  • When reinterpret_cast is used, virtual functions could lead a segmentation fault.
Name

0 weights,1,abstract class,1,active function,3,adam,2,Adapter,1,affine,2,argmax,1,back propagation,3,binary classification,3,blog,2,Bucket list,1,C++,11,Casting,1,cee,1,checkButton,1,cnn,3,col2im,1,columnspan,1,comboBox,1,concrete class,1,convolution,2,cost function,6,data preprocessing,2,data set,1,deep learning,31,Design Pattern,12,DIP,1,django,1,dnn,2,Don't Repeat Your code,1,drop out,2,ensemble,2,epoch,2,favicon,1,fcn,1,frame,1,gradient descent,5,gru,1,he,1,identify function,1,im2col,1,initialization,1,Lab,9,learning rate,2,LifeLog,1,linear regression,6,logistic function,1,logistic regression,3,logit,3,LSP,1,lstm,1,machine learning,31,matplotlib,1,menu,1,message box,1,mnist,3,mse,1,multinomial classification,3,mutli layer neural network,1,Non Virtual Interface,1,normalization,2,Note,21,numpy,4,one-hot encoding,3,OOP Principles,2,Open Close Principle,1,optimization,1,overfitting,1,padding,2,partial derivative,2,pooling,2,Prototype,1,pure virtual function,1,queue runner,1,radioButton,1,RBM,1,regularization,1,relu,2,reshape,1,restricted boltzmann machine,1,rnn,2,scrolledText,1,sigmoid,2,sigmoid function,1,single layer neural network,1,softmax,6,softmax classification,3,softmax cross entropy with logits,1,softmax function,2,softmax regression,3,softmax-with-loss,2,spinBox,1,SRP,1,standardization,1,sticky,1,stride,1,tab,1,Template Method,1,TensorFlow,31,testing data,1,this,2,tkinter,5,tooltip,1,Toplevel,1,training data,1,vanishing gradient,1,Virtual Copy Constructor,1,Virtual Destructor,1,Virtual Function,1,weight decay,1,xavier,2,xor,3,
ltr
item
Universe In Computer: 05. Virtual Function
05. Virtual Function
how to handle virtual function with cast
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvUavVsX4rYm8cgKQ8rzps7pHmmEVtkIb66G2o5KZFCfjvO96SCEUdaw_DMYzSbdVrB8XvnaKN8ljEE7EBjutI2XvsBL-2BLdijjJRIpAOEpvlhOW-hfWP3ir3wbE488AwdFEu7WKbLgO/s0/
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXvUavVsX4rYm8cgKQ8rzps7pHmmEVtkIb66G2o5KZFCfjvO96SCEUdaw_DMYzSbdVrB8XvnaKN8ljEE7EBjutI2XvsBL-2BLdijjJRIpAOEpvlhOW-hfWP3ir3wbE488AwdFEu7WKbLgO/s72-c/
Universe In Computer
https://kunicom.blogspot.com/2017/11/05-virtual-function.html
https://kunicom.blogspot.com/
https://kunicom.blogspot.com/
https://kunicom.blogspot.com/2017/11/05-virtual-function.html
true
2543631451419919204
UTF-8
Loaded All Posts Not found any posts VIEW ALL Readmore Reply Cancel reply Delete By Home PAGES POSTS View All RECOMMENDED FOR YOU LABEL ARCHIVE SEARCH ALL POSTS Not found any post match with your request Back Home Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sun Mon Tue Wed Thu Fri Sat January February March April May June July August September October November December Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec just now 1 minute ago 1 minutes ago 1 hour ago 1 hours ago Yesterday 1 days ago 1 weeks ago more than 5 weeks ago Followers Follow THIS CONTENT IS PREMIUM Please share to unlock Copy All Code Select All Code All codes were copied to your clipboard Can not copy the codes / texts, please press [CTRL]+[C] (or CMD+C with Mac) to copy