[C++ Visual Studio] порядок методов в vtable
class Base
{
virtual void Foo2;
virtual void Foo1;
};
class A : public Base
{
virtual void Foo1;
virtual void Foo2;
virtual void Foo3;
};
пойдёт такой пример?
пойдёт такой пример?ну я планировал другим опытом поделиться
но можно и это проанализировать:
сколько виртуальных таблиц здесь? в какой из них порядок функций будет не таким, как в объявлении класса? ну и вряд ли это VS-specific, правда?:)
делись своим примером, наверняка он не такой банальный
наверняка он не такой банальныйон менее банальный, но простой и там даже нет иерархий
весь пример в одном классе
весь пример
вот оно
ссылки по теме:
http://mingw-users.1079350.n2.nabble.com/vtables-incompatibl...
http://stackoverflow.com/questions/3243716/order-of-overload...
вот оноуверяю, подобные нюансы не от хорошей жизни мне известны
есть некая компания, которая предоставляет API в виде dll и интерфейсы (.h). Обратная совместимость достигается путем неудаления старых виртуальных функций и добавлением в конец новых. Так вот однажды они добавили в конец перегрузку виртуальной функции, которая уже раньше существовала. И старое приложение, загрузив их новую длл, стало падать. А падала она из особенности студии группировать методы в vtable по имени.
Был такой интерфейс
class AДобавили новый метод F2
{
virtual void F1(bla-bla1);
virtual void F2(bla-bla2);
virtual void F3(bla-bla3);
virtual void F4(bla-bla4);
};
таблица:
vtbl[0] = &F1;
vtbl[1] = &F2;
vtbl[2] = &F3;
vtbl[3] = &F4;
Приложуха вызывала F4 через vtbl[3];
class Aвот такие пироги
{
virtual void F1(bla-bla1);
virtual void F2(bla-bla2);
virtual void F3(bla-bla3);
virtual void F4(bla-bla4);
virtual void F2(bla-bla5);
};
таблица:
vtbl[0] = &F1;
vtbl[1] = &F2;
vtbl[2] = &F2 новый метод;
vtbl[3] = &F3;
vtbl[4] = &F4;
Приложуха пошла через vtbl[3]; и упала (видимо длл стала доставать аргументы метода)
зачем, зачем изобрели стандарты? Я тебя не осуждаю, я видел разные варианты нарушений стандартов. Но зачем люди это делают?
А что здесь стандарт нарушает?
Я полагаю, что vtbl - это undefined behaviour. И полагаться на него глупо
Я полагаю, что vtbl - это undefined behaviourподозреваю, ты что-то не так понял
попробую разъяснить этот момент:
Приложуха вызывала F4 через vtbl[3];в приложении такой код
#include "API.h"если в эту приложуху погрузить новую длл (с новой версией интерфейса API то она падать начинает
void foo(API* p)// p from thrid-party dll
{
p->F4;
}
в приложении не используется низкоуровневый доступ к таблице виртуальных функций, все на настоящем C++ =)
Видимо Айвенго имеет ввиду, что реализация таблицы виртуальных функций не описана в стандарте. Хотя вот ему встречный вопрос - что ж тогда, чисто сишным интерфейсом пользоваться в dll?
Моё знакомство с winAPI ограничено временами студенчества и поверхностно. Насколько я помню, подразумевается, что все ресурсы из dll выгружаются по уникальному строковому идентификатору.
Плюсовые библиотеки конечно имеют право на жизнь, но распространять софт в них - не лучшая идея.
Я полагаю, что vtbl - это undefined behaviour. И полагаться на него глупоunspecified. Undefined behaviour это совсем другой зверь, бро!
Не ну, а чо вы хотели?! Это примерно тоже самое, как поле новое в класс добавить - бинарная совместимость нарушается.
зачем, зачем изобрели стандарты? Я тебя не осуждаю, я видел разные варианты нарушений стандартов. Но зачем люди это делают?На мой взгляд, тут скорее надо смотреть не в сторону стандартов, а в сторону хороших практик. Умные люди говорят, что неприватные виртуальные методы (кроме деструктора) лучше не использовать, потому что виртуальный метод используется для реализации определенного поведения; интерфейс же лучше делать невиртуальным.
В данном контексте можно еще добавить, что обращение к функции или переменной по индексу, не имеющему самостоятельного смысла, - вещь очень ненадежная, даже если бы MSVC их расставлял в желаемом порядке.
И еще один момент: , надеюсь, вы не используете наследование от этих классов? Потому что если используете, то про совместимость на уровне ABI лучше забыть.
NVI - это же не общепринятая истина, если есть такая идиома, это не значит, что она обязана всегда применяться. К тому же ты легко можешь использовать NVI даже в этом случае, отнаследуйся от этого абстрактного класса, помести в наследник свой класс с NVI, и в реализациях виртуальных функций вызывай методы своего класса, всего-то.
, надеюсь, вы не используете наследование от этих классов?а как можно использовать абстрактные классы без наследования от них?
а как можно использовать абстрактные классы без наследования от них?во-первых, я не понял о каких именно проблемах тут фантазируют, даже если мы отнаследуемся от такого класса
во-вторых, от них нет надобности наследоваться, если они лишь предоставляют API:
lib = LoadLibrary("third-party.dll");в-третьих, да, мы наследуемся от thrid-party интерфейсов, т.к. через них делаются обратные вызовы
auto createFunc = lib.GetProcAddress<FactoryType>("factory_func");
API* p = createFunc;
p->InvokeSomething;
class MyCallback : public ThirdPartyInterfaceкстати, для колбеков тоже интересно сделана версионность, там тоже могут появляться методы, но для того, чтобы third-party.dll не вызвало несуществующий метод, мы передаем номер версии API в фабрику:
{
virtual void OnEvent {};
};
API* p = createFunc;
MyCallback c;
p->RegisterCallback(&c);
API* p = createFunc(API_VERSION);при таком подходе можно подкладывать более свежую длл и на основании версии она будет понимать можно ли вызывать у колбека какой-то метод
В данном контексте можно еще добавить, что обращение к функции или переменной по индексу, не имеющему самостоятельного смысла, - вещь очень ненадежная, даже если бы MSVC их расставлял в желаемом порядке.Ну таки да, было бы локально полегче, если бы это были не раздаваемые в лексикографическом порядке индексы от нуля, а нечто более осмысленное.
Труднее было бы в ногу попасть.
ну бери питон, там все это есть.
Блин, это же не свойство языка.
Оставить комментарий
Maurog
накину задачку по поводу, а заодно и поделюсь своим опытомзадачка актуально только для студий так что с гцц плиз не влезать!
в таблице виртуальных функций студия чаще всего располагает методы в порядке, указанном при объявлении класса, то есть для класса
виртуальная таблица будет иметь три записи-указателя на методы
Если добавить виртуальный деструктор, то не зависимо от его положения в объявлении класса в таблице он будет иметь индекс 0, остальные методы просто сдвинутся. Такое поведение могли заметить многие.
Однако в некоторых случаях студия может разместить методы в другом относительном порядке, нежели это указано в классе.
Внимание вопрос: приведите такой пример: в определении один метод перед вторым, а в таблице он после указателя на второй метод. Деструкторы по очевидным причинам не рассматриваем.