Вопрос

Почему, например, нет языковой поддержки для изучения виртуальной таблицы?Почему я не могу заменить функцию-член новой?У меня есть нутром ощущение, что есть способы использовать такие функции с пользой.

Существуют ли какие-либо другие языки, которые позволяют мне делать такие вещи?

Это было полезно?

Решение

Основная причина заключается в том, что сохранение vtable в качестве детали реализации позволяет любой конкретной реализации оптимизировать ее по своему усмотрению; это означает, что он может, например, обрезать или даже полностью исключить vtable, если он может доказать, что для данного метода (или всех методов) нет виртуальных вызовов. Или он может заменить отправку vtable проверкой типа if-else, если, например, он видит, что есть только несколько альтернатив (это может быть выгодно, потому что предсказание ветвлений будет работать в этом случае, но не с vtables, а также потому, что тогда могут быть встроены ветви if-else). Он может переупорядочивать методы в vtable так, что наиболее часто вызываемые из них появляются раньше, или так, что те, которые обычно вызываются один за другим, заполняют смежные слоты в vtable, чтобы использовать преимущества кэширования. И так далее. Конечно, все эти реализации также сделали бы макет vtable совершенно непредсказуемым и, следовательно, бесполезным, если бы он подвергался (в соответствии со спецификацией языка) реализации.

Кроме того, vtables не так просты, как кажется. Например, компиляторы часто должны генерировать thunks для исправления указателя this для таких вещей, как виртуальное наследование или множественное наследование в сочетании с ковариантными типами возвращаемых данных. Это опять то, что не имеет «единственного лучшего способа» чтобы сделать это (именно поэтому разные компиляторы делают это по-разному), и его стандартизация фактически потребует выбора конкретного способа.

Тем не менее, "Vtable Switching" является потенциально полезным методом, если он представлен в качестве конструкции более высокого уровня (так что оптимизация все еще возможна). Например, см. UnrealScript, который позволяет определить несколько состояний для класса (одно по умолчанию, другое named) и переопределить некоторые методы в именованных состояниях. Производные классы могут переопределять больше методов в существующих состояниях или добавлять свои собственные состояния и переопределять их. Кроме того, состояния могут расширять другие состояния (поэтому, если метод не переопределяется для определенного состояния, он возвращается к состоянию «родительского» и т. Д., Пока цепочка не достигнет состояния по умолчанию). Для актерского моделирования (какими по сути являются игры) все это имеет большой смысл, поэтому в UnrealScript оно есть. И очевидный эффективный механизм реализации для всего этого - переключение виртуальных таблиц, причем каждое состояние имеет отдельный виртуальный каталог.

Другие советы

Потому что это деталь реализации компилятора. Эта реализация может измениться, и любой код, который опирается на нее, будет в лучшем случае хрупким.

C ++ - это язык, на котором вы никогда не «платите» за то, что не используете. Такая поддержка во время выполнения противоречила бы этой философии.

Существует множество языков (на более динамичном конце спектра), которые поддерживают это.

Потому что он не должен быть реализован как VTable , хотя обычно это так. Короче говоря, в C ++ не существует такой вещи, как VTable !

JavaScript, Python и Ruby могут сделать это. В этих языках определения классов и экземпляров изменяются во время выполнения. Абстрактно, каждый объект и тип - это словарь переменных и методов-членов, которые можно изучать и обновлять.

Это невозможно в C ++, потому что это потребует возможности перезаписывать сгенерированный двоичный код, что может привести к значительным потерям производительности.

Vtables существуют только при определенных обстоятельствах в некоторых компиляторах (то есть они не указаны в стандарте, но являются деталями реализации). Даже когда они существуют, они возникают только тогда, когда у вас есть виртуальные функции и вам нужно косвенное обращение для реализации полиморфизма. Когда это не требуется, их можно оптимизировать, сохраняя издержки косвенного обращения при вызове.

К сожалению (или иным образом, в зависимости от вашего мнения по этому вопросу ;-), C ++ не был разработан для поддержки исправлений обезьян. В некоторых случаях (например, COM) vtable является частью реализации, и вы можете за кулисами копаться. Однако это никогда не будет поддерживаться или переноситься.

Я думаю, что вы можете делать такие вещи в динамических языках, таких как Python:

>>> class X():
...     def bar(self): print "bar"
...     
>>> x = X()
>>> x.bar()
bar
>>> def foo(x): print "foo"
... 
>>> X.bar = foo
>>> x.bar()
foo

Разница со статическим языком, таким как C ++, состоит в том, что интерпретатор ищет все имена во время выполнения и затем решает, что делать.

В C ++, скорее всего, есть другие решения для "замены функции-члена другой" проблема, самой простой из которых может быть использование указателей на функции:

#include <iostream>

class X;
typedef void (*foo_func)(const X&);

void foo(const X&) { std::cout << "foo\n"; }
void bar(const X&) { std::cout << "bar\n"; }

class X
{
    foo_func f;
public:
    X(): f(foo) {}
    void foobar() { f(*this); }
    void switch_function(foo_func new_foo) { f = new_foo; }
};

int main()
{
    X x;
    x.foobar();
    x.switch_function(bar);
    x.foobar();
}

(foo и bar не используют аргумент X & amp; в этом примере, аналогичном примеру Python)

Я работаю над статически скомпилированным языком, который выставляет vtable, и, поверьте мне, это немного волосы , чтобы выставить.

  • Все, что вы можете сделать на C++, вы можете сделать и на чистом C, приложив немного усилий.
  • Любая скромная и разумная программа на языке C должна компилироваться на C++.

Возможно, вам нужно реализовать свои собственные виртуальные таблицы, не используя встроенные возможности C++.Вы получите массу удовольствия от функций указателей на члены (ptmf)!

У вас возникнут проблемы с поиском компилируемого языка с интроспекцией vtable, поскольку на него мало спроса и его нелегко реализовать.Однако для интерпретируемых языков ситуация обратная.

  

Есть ли другие языки?   там, которые позволяют мне сделать такое   вещи?

Objective-C (и Objective-C ++) позволяет заменять уже скомпилированные методы во время выполнения. Это либо лучшая комбинация статических и динамических техник, либо худшая, в зависимости от того, кого вы спрашиваете.

Как уже отмечали другие, понятия «vtable» не существует. в стандарте C ++, так как это почти универсальный метод реализации, очень похожий на искажение имен.

Если вам нужна возможность переопределять функции на лету в скомпилированном языке, вас может заинтересовать Common Lisp. Должны быть и другие, но единственные другие языки, о которых я могу думать, имеют либо статическое наследование и функции, либо интерпретируются с высокой производительностью.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top