#include <stdio.h>
class CEmpty
{
public:
virtual ~CEmpty() {};
};
class CEmpty2
{
public:
virtual ~CEmpty2() {};
virtual void nothing() {};
};
class CEmpty3
{
public:
virtual ~CEmpty3() {};
virtual void nothing() {};
virtual void something() {};
};
int main()
{
CEmpty empty;
printf("size of CEmpty object is %d\r\n", sizeof(empty));
CEmpty2 empty2;
printf("size of CEmpty2 object is %d\r\n", sizeof(empty2));
CEmpty3 empty3;
printf("size of CEmpty3 object is %d\r\n", sizeof(empty3));
return 0;
}
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7s3HjJRvjKnVVHjSyGbP7IhLR3ky577lqyT4nUQk52NJ66YidNgI59ikBxzFYRfJRqfsXiFHgLfnQgqjv9kMsj1LK0Z9rfbihfj3yORROeGwAy7nH-q9IK30XN6AgtVltD-bctXyYQUI/s400/Size+Of+CEmpty+with+virtual+methods.png)
Програмки из предыдущей части, если классы имеют виртуальные функции, не работают.
Если посмотреть память, то видно, что переменные передвинулись на 4 байта в памяти от "начала" класса:
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlI4vwvERdGSQ3TZkq9B11q5tWZqMxSJKDW3AstNYCYUNO_c5lIAMScR6Vsl1QEB9PXDjAbXrFKkTbj4_BFk4x8_GVF7mEAWOLIqIyTPuFpdQsZL-Ksdcv9rrFXVCkv_i8A2bby-HM9nY/s400/MEMORY+WITH+VIRTUAL+METHODS.png)
Это хорошо видно, если использовать класс со строкой из предадущих примеров:
#include <stdio.h>
#include <Windows.h>
class CCharArray
{
char x[24];
public:
CCharArray()
{
strcpy(x, "Hello");
}
virtual void out()
{
printf("x is %s\r\n", x);
}
};
int main()
{
CCharArray objCharArray;
printf("size of CCharArray object is %d\r\n", sizeof(objCharArray));
printf("CCharArray as string is %s\r\n", (char*)&objCharArray);
objCharArray.out();
return 0;
}
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5DGNhhKN-qWTXX95tvO2hl50Qg0xdFs74cJn870jZGC4_OrbVRTK9G61g8UsMD_G_glzxkrMlSTutH7hE4paxJluKTCt04G3iCCZ1EsLL9OMy2eukt3AGl_mNxfXdKfauzhjrgB3kCkI/s400/string+virtual.png)
Строка
printf("CCharArray as string is %s\r\n", (char*)&objCharArray);
не работает.
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimsQSeucsKYYrYLyzlOnvhEKjyqb4xCS0dFsoHkJ-KnuxqWjYJBQZuqrKGv9Cw2cFyF6sirQ_Es6ifvVLHhtIxYPv9s1OCuBKGCIxmlN5K6iuG-yybFj-NSCVC4IjGoJoIDIjVNveaFrw/s400/stringMEMORY+WITH+VIRTUAL+METHODS.png)
Добавили только виртуальный метод. Память изменилась. Вывод - это указатель на виртуальные функции. Точнее - на таблицу виртуальных функций. Эту таблицу можна просмотреть:
#include <stdio.h>
class C1Int
{
int x;
public:
virtual void test()
{
printf("C1Int::test()\r\n");
}
};
class C2Int : public C1Int
{
int y;
public:
virtual void test()
{
printf("C2Int::test()\r\n");
}
virtual void test1()
{
printf("C2Int::test1()\r\n");
}
virtual void test2()
{
printf("C2Int::test2()\r\n");
}
};
int main()
{
C2Int two_int;
printf("size of C2Int object is %d\r\n", sizeof(two_int));
printf("Address of C2Int object is %p\r\n", &two_int);
int* p = (int*)(&two_int);
printf("Address of C2Int pointer is %p\r\n", p);
int p1 = *((int*)(&two_int));
printf("Value of this pointer is %x\r\n", p1);
int* _p1 = (int*)*((int*)(&two_int));
printf("Same.. pointer is %p\r\n", _p1);
int* p2_1 = (int*)*((int*)*(int*)(&two_int));
printf("Value of first entry of C2Int VTable is %p\r\n", p2_1);
int* p2_2 = (int*)*((int*)*(int*)(&two_int) + 1);
printf("Value of second entry of C2Int VTable is %p\r\n", p2_2);
int* p2_3 = (int*)*((int*)*(int*)(&two_int) + 2);
printf("Value of third entry of C2Int VTable is %p\r\n", p2_3);
int* p2_4 = (int*)*((int*)*(int*)(&two_int) + 3);
printf("Value of fourth entry of C2Int VTable is %p\r\n", p2_4);
int* p2_5 = (int*)*((int*)*(int*)(&two_int) + 4);
printf("Value of fifth entry of C2Int VTable is %p\r\n", p2_5);
return 0;
}
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL5Xfg9e-ic9jAYhpKAbz9NuK2-lJ3Roym_sepIMEWdc0ss-do5g84sH1lsma33XVxZ9vZZdmOHI8N6JUsn-phWZ2-hp4V9uEAfGLotzzUl3zKewd4oF8S1xFGxoYF7kjyA7_auWCXBs8/s400/virtual+table.png)
C2Int class имеет только 3 виртуальных метода, но программа пытается найти 5. Эта "ошибка" показывает, что таблица заканчивается нулем.
Функции нашлись. Их и вызвать можна не спрашивая разрешения у класса:
#include <stdio.h>
class C1Int
{
public:
virtual void test()
{
printf("C1Int::test()\r\n");
}
};
class C2Int : public C1Int
{
public:
virtual void test()
{
printf("C2Int::test()\r\n");
}
virtual void test1()
{
printf("C2Int::test1()\r\n");
}
virtual void test2()
{
printf("C2Int::test2()\r\n");
}
};
typedef void (* func)();
int main()
{
C2Int two_int;
printf("size of C2Int object is %d\r\n", sizeof(two_int));
printf("Address of C2Int object is %p\r\n", &two_int);
int* p = (int*)(&two_int);
printf("Address of C2Int pointer is %p\r\n", p);
int p1 = *((int*)(&two_int));
printf("Value of this pointer is %x\r\n", p1);
int* _p1 = (int*)*((int*)(&two_int));
printf("Same.. pointer is %p\r\n", _p1);
int* p2_1 = (int*)*((int*)*(int*)(&two_int));
printf("Value of first entry of C2Int VTable is %p\r\n", p2_1);
int* p2_2 = (int*)*((int*)*(int*)(&two_int) + 1);
printf("Value of second entry of C2Int VTable is %p\r\n", p2_2);
int* p2_3 = (int*)*((int*)*(int*)(&two_int) + 2);
printf("Value of third entry of C2Int VTable is %p\r\n", p2_3);
func f1 = (func)p2_1;
f1();
f1 = (func)p2_2;
f1();
f1 = (func)p2_3;
f1();
C1Int one_int;
func f2 = (func)((int*)*((int*)*(int*)(&one_int)));
f2();
return 0;
}
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih4xtrtBjO93XjnLJfblnOfPT0lssxIGD9mtx_zYGV_K_I_fLWiw6e44oJLkt2qMhFm57lUhx2VEgsF1o1m7AGQ4hbXJ8ubT7gwl8LxacJeOgtdh6rcGMqKlXVxeSPaE5Df2rYKR0xxWg/s400/call+virtual+table.png)
No comments:
Post a Comment