ATL Under the Hood Part 2

Let's explore some more interesting stuff behind the virtual function. To make things consistent with my previous article, I am going to take the same number sequence and start my discussion with Program 20.

Take a look at the following Program

Program 20

#include <iostream>
using namespace std;

class Base {
public:
  virtual void fun() {
    cout << "Base::fun" << endl;
  }
  void show() {
    fun();
  }
};

class Drive : public Base {
public:
  virtual void fun() {
    cout << "Drive::fun" << endl;
  }
};

int main() {
  Drive d;
  d.show();

  return 0;
}

The output of the program is

Drive::fun

This program clearly shows how the base class's function calls the drive class function if that function is virtual. This technique is used in different frameworks like MFC and design pattern like Template Design Pattern. Now change program little bit to see its behavior. Now I m going to call virtual function from constructor of Base class rather than member function.

Program 21

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    fun();
  }
  virtual void fun() {
    cout << "Base::fun" << endl;
  }
};

class Drive : public Base {
public:
  virtual void fun() {
    cout << "Drive::fun" << endl;
  }
};

int main() {
  Drive d;

  return 0;
}

The output of this program is

Base::fun

This program shows that we can't call virtual function of drive class from constructor of base class. To see what is going on under the hood let's print the value of this pointer in both constructors. To make things simple remove other functions from the classes.

Program 22

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "This Pointer = " << (int*)this << endl;
    cout << endl;
  }
virtual void f() { cout << "Base::f" << endl; }
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "This Pointer = " << (int*)this << endl;
    cout << endl;
  }
virtual void f() { cout << "Drive::f" << endl; }
};

int main() {
  Drive d;
  cout << "In Main" << endl;
  cout << (int*)&d << endl;

  return 0;
}

The output of the program is

In Base
This Pointer = 0012FF7C

In Drive
This Pointer = 0012FF7C

In Main
0012FF7C

This shows that there is only one object in the memory location. Now let's print the value at this pointer, i.e. value of vptr and address of VTable.

Program 23

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Base::f1" << endl; }
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Drive::f2" << endl; }
};

int main() {
  Drive d;
  return 0;
}

The output of this program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C08C
Value at Vtable = 004010F0

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C07C
Value at Vtable = 00401217

This program shows the different vtable address in Base class and Drive class. To get more better understanding lets make inheritance more deep and add one more class MostDrive inherited from Drive and make an object of it.

Program 24

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Base::f1" << endl; }
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Drive::f2" << endl; }
};

class MostDrive : public Drive {
public:
  MostDrive() {
    cout << "In MostDrive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    cout << endl;
  }
  virtual void f1() { 
    cout << "MostDrive::f2" << endl; 
  }
};

int main() {
  MostDrive d;
  return 0;
}

The output of this program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0A0
Value at Vtable = 004010F5

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C090
Value at Vtable = 00401221

In MostDrive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C080
Value at Vtable = 00401186

This program shows that virtual pointer in initialized in constructor of each class. Therefore the address of Vtable is different in each class constructor and main use the vtable of most drive class in inheritance chain whose object is created.

Now see what each class constructor place in vtable. To do this take pointer to function and store value of first entry of vtable in that function pointer and try to execute it.

Program 25

#include <iostream>
using namespace std;

typedef void(*Fun)();

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;

    Fun pFun = (Fun)*(int*)*(int*)this;
    pFun();
    cout << endl;
  }
  virtual void f1() { cout << "Base::f1" << endl; }
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    
    Fun pFun = (Fun)*(int*)*(int*)this;
    pFun();
    cout << endl;
  }
  virtual void f1() {
     cout << "Drive::f1" << endl; 
  }
};

class MostDrive : public Drive {
public:
  MostDrive() {
    cout << "In MostDrive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable = " 
         << (int*)*(int*)*(int*)this << endl;
    
    Fun pFun = (Fun)*(int*)*(int*)this;
    pFun();
    cout << endl;
  }
  virtual void f1() { 
    cout << "MostDrive::f1" << endl;
  }
};

int main() {
  MostDrive d;
  return 0;
}

The output of this program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C098
Value at Vtable = 004010F5
Base::f1

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C088
Value at Vtable = 00401221
Drive::f1

In MostDrive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C078
Value at Vtable = 00401186
MostDrive::f1

This program shows that constructor of each class fills the vtable entries with their own virtual function. So Base class fill vtable with the address of Base virtual function and when Drive class's constructor execute it will create another vtable and store the virtual functions address.

Now see the situation when there is more than one virtual function in the base class and drive class override not all of these.

Program 26

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << "Value at Vtable 3rd entry = " 
         << (int*)*((int*)*(int*)this+2) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Base::f1" << endl; }
  virtual void f2() { cout << "Base::f2" << endl; }
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << "Value at Vtable 3rd entry = " 
         << (int*)*((int*)*(int*)this+2) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Drive::f1" << endl; }
};

int main() {
  Drive d;
  return 0;
}

The output of this program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0E0
Value at Vtable 1st entry = 004010F0
Value at Vtable 2nd entry = 00401145
Value at Vtable 3rd entry = 00000000

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C8
Value at Vtable 1st entry = 0040121C
Value at Vtable 2nd entry = 00401145
Value at Vtable 3rd entry = 00000000

The output of this program shows that the base class' virtual function is not overridden in drive class then drive class constructor doesn't do anything with that entry in virtual function.

Now let's invite a pure virtual function into this game and see its behavior. Take a look at the following program

Program 27

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Drive::f1" << endl; }
  virtual void f2() { cout << "Drive::f2" << endl; }
};

int main() {
  Drive d;

  return 0;
}

The output of this program is little bit different in debug and release mode. Here is the output of the debug mode

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0BC
Value at Vtable 1st entry = 00420CB0
Value at Vtable 2nd entry = 00420CB0

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0A4
Value at Vtable 1st entry = 00401212
Value at Vtable 2nd entry = 0040128F

And here is the output in the release Mode

In Base
Virtual Pointer = 0012FF80
Address of Vtable = 0042115C
Value at Vtable 1st entry = 0041245D
Value at Vtable 2nd entry = 0041245D

In Drive
Virtual Pointer = 0012FF80
Address of Vtable = 00421154
Value at Vtable 1st entry = 00401310
Value at Vtable 2nd entry = 00401380

To better understand this, let's change the program a little bit and try to call virtual function from a function pointer.

Program 28

#include <iostream>
using namespace std;

typedef void(*Fun)();

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    
    // try to execute first virtual function
    Fun pFun = (Fun)*((int*)*(int*)this+0);
    pFun();

    cout << endl;
  }
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "Drive::f1" << endl; }
  virtual void f2() { cout << "Drive::f2" << endl; }
};

int main() {
  Drive d;

  return 0;
}

Now the behavior ofthe program is different in debug and release Mode. In Debug mode it displays a run time error dialog box:

And when you press the Ignore button, one more dialog is displayed:

In release mode it just displays the error message in the output console window.

In Base
Virtual Pointer = 0012FF80
Address of Vtable = 0042115C
Value at Vtable 1st entry = 0041245D
Value at Vtable 2nd entry = 0041245D

runtime error R6025
- pure virtual function call

What is the R6025 runtime error? It is defined in CMSGS.H file which define all error messages used within the C run time library.

#define _RT_PUREVIRT_TXT   "R6025" EOL \
        "- pure virtual function call" EOL

In fact when you define a pure virtual function, the compiler places the address of one of the C Runtime library function _purecall. This function is define in PUREVIRT.C and have the following prototype.

void __cdecl _purecall(void)

We can achieve the same behavior by directly calling this function from a program. Let's take a look at this in a very small program.

Program 29

int main() {
  _purecall();  
  return 0;
}

The output of this program is same as previous one in both debug and release mode. To better understand this make the inheritance chain deeper and drive one more class from Drive and see the behavior of this.

Program 30

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
};

class MostDrive : public Drive {
public:
  MostDrive() {
    cout << "In MostDrive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "MostDrive::f1" << endl; }
  virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
  MostDrive d;

  return 0;
}

The output of this program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0D8
Value at Vtable 1st entry = 00420F40
Value at Vtable 2nd entry = 00420F40

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420F40
Value at Vtable 2nd entry = 00420F40

In MostDrive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0A8
Value at Vtable 1st entry = 00401186
Value at Vtable 2nd entry = 004010F5

This program shows that both Base and Drive classes make their own virtual table and initialized it with the same value. Now what happen if the inheritance is deeper and none of the class except the most drive overrides any pure virtual function? This happens in the case of COM programming where interfaces are class with only pure virtual function and one interface is inherited from another interface and only implementation class override the pure virtual function of interfaces. Then each base class constructor makes their own vtable and put the same value in its entry. So it means duplication of same code again and again.

The main philosophy of ATL is to make COM component as small as possible, but due to this behavior interface class' constructor have lot of unnecessary code. To solve this problem ATL introduce a macro ATL_NO_VTABLE define in ATLDEF.H file as

#define ATL_NO_VTABLE __declspec(novtable)

__declspec(novtable) is Microsoft C++ specific extended attribute of class. When it is used then compiler won't generate the code to initialize the vptr and vtable and reduce the generated code size.

Change our program little bit to better understand this what this attribute can do for us.

Program 31

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
};

class __declspec(novtable) MostDrive : public Drive {
public:
  MostDrive() {
    cout << "In MostDrive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "MostDrive::f1" << endl; }
  virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
  MostDrive d;

  return 0;
}

The output of this program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0CC
Value at Vtable 1st entry = 00420E60
Value at Vtable 2nd entry = 00420E60

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0B4
Value at Vtable 1st entry = 00420E60
Value at Vtable 2nd entry = 00420E60

In MostDrive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0B4
Value at Vtable 1st entry = 00420E60
Value at Vtable 2nd entry = 00420E60

This program shows one more result i.e Drive and MostDrive class have the same value in its vptr, but Base class have different. In fact this is due to that we haven't use __declspec(novtable) attribute with Base class. Now change program little bit and inherit Drive class with the same attributes i.e. __declspec(novtable)

Program 32

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class __declspec(novtable) Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
};

class __declspec(novtable) MostDrive : public Drive {
public:
  MostDrive() {
    cout << "In MostDrive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() { cout << "MostDrive::f1" << endl; }
  virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
  MostDrive d;

  return 0;
}

Now the output of the program is

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420E50
Value at Vtable 2nd entry = 00420E50

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420E50
Value at Vtable 2nd entry = 00420E50

In MostDrive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420E50
Value at Vtable 2nd entry = 00420E50

In MSDN it is written about __declspec(novtable) that it should be applied to pure virtual classes. Let's do one more experiment to understand meaning of this better.

Program 33

#include <iostream>
using namespace std;

class Base {
public:
  Base() {
    cout << "In Base" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) 
         << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class __declspec(novtable) Drive : public Base {
public:
  Drive() {
    cout << "In Drive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;
  }
};

class __declspec(novtable) MostDrive : public Drive {
public:
  MostDrive() {
    cout << "In MostDrive" << endl;
    cout << "Virtual Pointer = " 
         << (int*)this << endl;
    cout << "Address of Vtable = " 
         << (int*)*(int*)this << endl;
    cout << "Value at Vtable 1st entry = " 
         << (int*)*((int*)*(int*)this+0) << endl;
    cout << "Value at Vtable 2nd entry = " 
         << (int*)*((int*)*(int*)this+1) << endl;
    cout << endl;

    // try call first virtual function
    typedef void (*Fun)();
    Fun pFun = (Fun)*((int*)*(int*)this+0);
    pFun();

  }
  virtual void f1() { cout << "MostDrive::f1" << endl; }
  virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
  MostDrive d;

  return 0;
}

Here the new thing we add in this program is

    // try call first virtual function
    typedef void (*Fun)();
    Fun pFun = (Fun)*((int*)*(int*)this+0);
    pFun();

And when we run the application we face the same problem as previous i.e. try to call pure virtual function. It means the virtual table haven't initialized yet. MostDrive class is not an abstract class so we should remove __declspec(novtable) from this class.

Program 34

#include <iostream>
using namespace std;

class Base {
public:
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class __declspec(novtable) Drive : public Base {
};

class MostDrive : public Drive {
public:
  MostDrive() {

    // try call first virtual function
    typedef void (*Fun)();
    Fun pFun = (Fun)*((int*)*(int*)this+0);
    pFun();

  }
  virtual void f1() { cout << "MostDrive::f1" << endl; }
  virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
  MostDrive d;

  return 0;
}

Now this programs work fine and output of this program is

MostDrive::f1

It is not necessary to use this attribute in ATL class only; it can be used with any class whose object can not be created. In the same way it is not necessary to must use this with ATL class, this can be omitted from ATL class, but removing this from ATL class can generate more code.

Hope to explore some other mysterious of ATL in next article.



About the Author

Zeeshan Amjad

C++ Developer at Bechtel Corporation. zamjad.wordpress.com

Comments

  • Thank you for your article

    Posted by Legacy on 11/11/2002 12:00am

    Originally posted by: Ken

    Reply
  • Nice

    Posted by Legacy on 03/28/2002 12:00am

    Originally posted by: Ola Berntsson

    Under-the-hood articles rock - understanding the memory
    
    layout of any code really helps you in taking the right
    decisions when desinging software, specifically when
    there are performance issues.

    The examples are good, although I would prefer printf()
    rather than std::cout for cleaner code.

    Reply
  • 404 - File not found (Part1)

    Posted by Legacy on 03/26/2002 12:00am

    Originally posted by: Link Error

    The link to the first part of your article is not available.
    Interesting Read!
    Thanx.

    Reply
  • Program 33

    Posted by Legacy on 02/20/2002 12:00am

    Originally posted by: Jefferson Liu

    I comment out the pFun() call in the constructor of class MostDrive, and change the main() function as following:
    
    int main() {
    MostDrive d;
    d.f1(); // MostDrive::f1

    MostDrive* pd = &d;
    pd->f1(); // pure virtual function call

    return 0;
    }

    why d.f1() and pd->f1() not behave identically?

    Reply
  • Wow! I got clear concept now.

    Posted by Legacy on 02/19/2002 12:00am

    Originally posted by: Syed Aoun Raza

    Hi, You did great Man, Cause before reading this article my concept was dangling around but now it is cleared that how we can work using the virtual functions, Keep it up.

    Reply
  • Nice Article!

    Posted by Legacy on 02/19/2002 12:00am

    Originally posted by: kyle

    Nice job with the article. I look forward to your upcoming articles on ATL. The examples made it easy to follow so hope you keep the same format in your upcoming articles.

    Reply
  • Zeeshan rocks!

    Posted by Legacy on 02/16/2002 12:00am

    Originally posted by: amit dey

    Loved the Under the hood articles - I thought I knew just about everything in ATL, but even I picked up a couple of pointers(literally):) here.
    Keep up the good work.

    Reply
  • Great One

    Posted by Legacy on 02/15/2002 12:00am

    Originally posted by: Shrishail Rana

    I always have a confusion on Virtual function and your article helped me a lot. Not even from ATL perspective it is great.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds