Почему методы класса меняются местами при использовании различных компиляторов?

111
26 мая 2019, 19:10

Имеется DLL C++ скомпилированная на MSVC. При динимической подгрузке DLL инициализируется фабрика и создает класс который используется дальше.

Пример описания возвращаемого класса на C++ MSVC:

class Test
{
    virtual void Call(int t);
    virtual void Call(wchar_t* t);
    virtual void F(wchar_t* t);
    virtual void Call(double t);
};

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

Пример описания этого же класса C++ (C++ Builder):

class Test
{
    virtual void Call(double t);
    virtual void Call(wchar_t* t);
    virtual void Call(int t);
    virtual void F(wchar_t* t);
};

И собственно, точно так же мне необходимо менять местами методы в Delphi.

Пример описания на Delphi:

type
    Test = class
    procedure Call(t: Double); overload; virtual; abstract;
    procedure Call(t: PChar); overload; virtual; abstract;
    procedure Call(t: Integer); overload; virtual; abstract;
    procedure F(t: PChar); overload; virtual; abstract;
end;

Почему это происходит? Какой из компиляторов производит данную оптимизацию и возможно ли как то ее избежать? Либо же заставить производить ее оба компилятора?

Answer 1

МSVС++ группирует виртуальные функции одного класса по именам функций. Порядок следования групп соответствует порядку первого появления какой-нибудь функции из группы в исходном файле. Затем внутри каждой группы порядок следования функций заменяется на обратный (по отношению к порядку объявления в исходном файле). Полученный в результате порядок - это и есть порядок в виртуальной таблице.

Именно это вы и наблюдаете в вашем случае. То есть сначала вы получаете две группы

virtual void Call(int t);
virtual void Call(wchar_t* t);
virtual void Call(double t);
virtual void F(wchar_t* t);

(именно в таком порядке следования групп), а затем порядок внутри каждой группы меняется на обратный

virtual void Call(double t);
virtual void Call(wchar_t* t);
virtual void Call(int t);
virtual void F(wchar_t* t);

Вот так будет выглядеть виртуальная таблица в MSVC++.

Таким образом пока вы не пользуетесь перегрузкой функций, функции в виртуальной таблице будут идти в порядке объявления. Но как только в вашем классе появляются функции с одинаковыми именами, начинается вот такое переупорядочение.

Разумеется, такая группировка выполняется только среди новых функций каждого отдельного класса. Если в классе-наследнике вы добавите функции с теми же именами, но с другими сигнатурами, то все новые функции в виртуальной таблице будут добавлены после функций предка. Но опять же, среди добавленных функций группировка и переупорядочение будут делаться по вышеописанным правилам.

READ ALSO
Перевод целых и вещественный чисел в массив символов(char) без использования стандартных функций

Перевод целых и вещественный чисел в массив символов(char) без использования стандартных функций

Необходимо написать функции перевода вещественных и целых чисел в строку без функцийПервую функцию написал

124
boost::asio::socket_base::reuse_address

boost::asio::socket_base::reuse_address

Доброго времени суток!

118
Адрес элемента из указателя на вектор

Адрес элемента из указателя на вектор

У меня есть указатель на вектор std::vector*Как получить адрес элемента i этого вектора?

111
Переполнение Metaspace

Переполнение Metaspace

В Java, начиная с 8 версии, появилась новая вариация OutOfMemory error : Metaspace

100