Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / ATL
Article

ATL Under the Hood - Part 2

Rate me:
Please Sign up or sign in to vote.
4.90/5 (36 votes)
17 Feb 2002CPOL6 min read 154.6K   112   17
This is article 2 in a series of tutorials that discuss some of the inner workings of ATL and the techniques that ATL uses.

Introduction

In this series of tutorials I am going to discuss some of the inner workings of ATL and the techniques that ATL uses. This is the second article in the series.

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

Let's 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 a virtual function of a derived  class from constructor of a base class. Ok 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 deeper 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 the 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 fills the vtable with the address of the Base's virtual functions and when Drive class's constructor executes 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's virtual function is not overridden in drive class then drive class constructor doesn't do anything with that entry in virtual function.

Now invite pure virtual function in this game too and see the behavior of it. 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 change a program little bit and try to call virtual function from 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 of program is different in debug and release Mode. In Debug mode it display run time error dialog box

And when you press Ignore button then it display one more dialog

And 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
Here what is R6025? 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 we define pure virtual function then compiler place 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 our program. Let's take a look at this very small program.

Program 29

int main() {
    _purecall();    
    return 0;
}
The out put 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 class make their own virtual table and initialized it with the same value. Now what happen if the inheritance is further deep 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's 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader American Institute for Research
United States United States
Working as a Team leader in American Institute for Research

Comments and Discussions

 
QuestionWhere does VTABLE is stored? Pin
prakashjoshi010118-Oct-07 3:14
prakashjoshi010118-Oct-07 3:14 
GeneralTrapping R6025 Pin
Satish Marathe29-Apr-04 2:36
Satish Marathe29-Apr-04 2:36 
Hi,

I wanted to trap the R6025 runtime error.
Do you have an idea how it can be done.

I tried try catch, onexit , at exit options but they dont work.

regards
Satish Marathe
GeneralRe: Trapping R6025 Pin
Anonymous11-Jan-05 10:59
Anonymous11-Jan-05 10:59 
GeneralI am learning ATL now, these articles help me a lot! Pin
samsuncn17-Jun-03 17:14
susssamsuncn17-Jun-03 17:14 
Generalprogram 23, 24, ... trouble Pin
vetalman31-Oct-02 1:45
vetalman31-Oct-02 1:45 
GeneralConfused Pin
Sparticus24-Jun-02 10:15
Sparticus24-Jun-02 10:15 
GeneralNevermind Pin
Sparticus24-Jun-02 11:55
Sparticus24-Jun-02 11:55 
GeneralRe: Nevermind Pin
shaochen19807-Aug-03 6:09
shaochen19807-Aug-03 6:09 
Generalthe length of app Pin
cristi negoita7-Mar-02 22:03
cristi negoita7-Mar-02 22:03 
GeneralRe: the length of app Pin
sapiens9-Mar-02 1:25
sapiens9-Mar-02 1:25 
Generalzackly the kinda stuff I like to try... Pin
7-Mar-02 14:04
suss7-Mar-02 14:04 
Generalchange a little bit Pin
Chen Jiadong22-Feb-02 3:57
Chen Jiadong22-Feb-02 3:57 
GeneralRe: change a little bit......... Pin
22-May-02 10:17
suss22-May-02 10:17 
GeneralRe: change a little bit Pin
Peter Lee26-Jul-02 11:59
Peter Lee26-Jul-02 11:59 
GeneralHey,,, Thank you... Pin
19-Feb-02 20:46
suss19-Feb-02 20:46 
Generalnice article Pin
archana18-Feb-02 20:21
archana18-Feb-02 20:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.