2009-09-12 2 views
1

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

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

+3

Я уверен, что возиться с vtable будет * не * сделать код более читаемым/безопасным/надежным. – Bombe

+0

Если бы была поддержка языка для этого, я бы не стал считать это «беспорядочным». Это будет понятная и широко используемая практика программирования. –

+0

Да, но нет, так что ... –

ответ

5

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

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

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

17

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

8

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

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

+0

Не могли бы вы назвать некоторые языки, которые поддерживают это. Голос в моей голове говорит о JavaScript и Python ... но не совсем уверен. –

+0

Я не знаю конкретно, поддерживается ли это JavaScript или Python, но это определенно поддерживается Ruby. –

+0

Для действительно мощной объектной системы найдите «CLOS» и «MOP». – gimpf

8

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

3

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

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

2

Я считаю, что вы можете делать такие вещи, что в динамических языках, как 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 и бар не использовать X & аргумент, в этом примере аналогичен примеру Python)

1

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

3

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

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

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

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

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

0

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

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

1

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

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