У меня есть сомнения по поводу виртуальной таблицы C ++ в последнее время.
Почему C ++ использует виртуальную таблицу?
=> Потому что компилятор C ++ не знает фактический адрес функции
—> Почему?
=> Поскольку компилятор C ++ не знает точный тип (Cat? Dog? Animal?) Объекта, на который указывает указатель «panimal»
—Зачем? Это каким-то образом компилятор может выяснить тип объекта?
=> Да, я думаю, что компилятор может сделать это через тип отслеживаемого объекта.
Давайте рассмотрим источники, где указатель объекта получает свое значение. Действительно 2 источника.
Таким образом, путем отслеживания потока присваивания назад к исходному объекту
=> Компилятор может определить точный тип указателя.
=> компилятор знает адрес вызываемой функции
=> Виртуальная таблица не требуется.
Отслеживание типа объекта сохраняет как виртуальную таблицу, так и виртуальную таблицу, указатель каждого экземпляра класса.
Где не работает отслеживание типов объектов?
Связывание библиотек.
Если библиотечная функция возвращает указатель базового класса, компилятор не может отследить исходный объект-источник. Может компилятор может адаптироваться к коду библиотеки и коду без библиотеки. Для библиотечных классов, которые экспортируются, используйте виртуальную таблицу. Для других классов просто отслеживайте их тип объекта для экономии памяти.
Я не уверен, есть ли какая-либо ошибка в вышеприведенных утверждениях, пожалуйста, укажите ее, если таковая имеется Заранее спасибо ~
В некоторых случаях, да, компилятор может определить тип, на который указывает указатель во время компиляции. Это довольно легко построить случай, когда он не может, хотя.
int x;
cin >> x;
Animal* p;
if (x == 10)
p = new Cat();
else
p = new Dog();
Если компилятор во всех случаях может доказать тип объекта, он может удалить виртуальные таблицы из своего сгенерированного кода в соответствии с правилом «как будто».
Компилятор может определить точный тип указателя.
да, но как вы хотите, чтобы он вызывал правильную функцию во время выполнения? Компилятор знает, но у С ++ нет виртуальной машины, которая могла бы сказать ему тип объекта, передаваемого во время выполнения, следовательно, потребность в виртуальной таблице для виртуальных функций унаследованных типов.
Вы бы предпочли, чтобы компилятор создавал код для всех различных путей кода, которые приводят к выполнению каждой виртуальной функции, чтобы он вызывал нужную функцию во время выполнения? Это привело бы к гораздо большим бинарным файлам, если это вообще возможно.
В этом примере становится ясно, что независимо от статического анализа кода, который может выполнить компилятор, фактический метод, вызываемый при ptrA-> f (); может быть известно только во время выполнения.
#include <sys/time.h>
#include <iostream>
#include <stdlib.h>
struct A {
virtual int f()
{
std::cout<<"class A\n";
}
};
struct B: public A {
int f()
{
std::cout<<"class B\n";
}
};
int main()
{
A objA;
B objB;
A* ptrA;
timeval tv;
gettimeofday(&tv, NULL);
unsigned int seed = (unsigned int)tv.tv_sec;
int randVal = rand_r(&seed);
if( randVal < RAND_MAX/2)
{
ptrA=&objA;
}
else
{
ptrA=&objB;
}
ptrA->f();
return 0;
}`