Разве чистый абстрактный класс C ++, объявленный в заголовке, который используется в разных проектах (без компиляции во время компиляции), использует одну и ту же модель виртуальной таблицы? - PullRequest
1 голос
/ 08 февраля 2012

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

Ответы [ 4 ]

2 голосов
/ 08 февраля 2012

Если я правильно понимаю, у вас есть что-то вроде этого:

хиджры

class A
{
public:
    virtual void foo()=0;
}

B.cpp

#include <A.h>

class B : public A
{
public:
    void foo()
    {}
}

C.cpp

#include <A.h>

void bar(A * a)
{}

Итак, B.cpp имеет класс, реализующий A, а C.cpp имеет некоторую функцию, принимающую указатель на экземпляр A (который вы предоставляете с экземпляром B). Это правильно?

Если это так, то да, они разделяют виртуальную таблицу. Vtable создается путем компиляции класса B, а C.cpp вообще не имеет собственных vtables.

2 голосов
/ 08 февраля 2012

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

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

Doozy вопроса, чтобы прочитать, кстати ...

1 голос
/ 08 февраля 2012

Это все зависит от компилятора, но в целом, когда класс является чисто виртуальным, и ни одна из функций-членов не определена в модуле перевода, компилятор сгенерирует vtable как слабый символ , В вашем конкретном случае различные единицы перевода будут генерировать отдельные, точно равные vtable s для базового типа, и компоновщик / загрузчик будет отбрасывать все символы, кроме одного, как это было бы с любым другим слабым символом (подумайте о шаблонном встроенная функция).

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

1 голос
/ 08 февраля 2012

Вы в безопасности.

Порядок, в котором методы появляются в vftable, определяется структурой базового класса, и это все, что вам нужно.Но это зависит от компилятора, поэтому используйте тот же компилятор для генерации DLL.Не полагайтесь на их обратную совместимость (или хотя бы проверяйте документацию).

Предположим, у вас есть следующий заголовок:

//header.h

class A
{
public:
    virtual void foo() = 0;
    virtual void goo() = 0;
};

И у вас есть B.dll со следующимкласс:

class B : public A
{
public:
    virtual void foo() {}
    virtual void goo() {}
}

Теперь в X.dll вы получаете указатель на A, который является B объектом, созданным в B.dll.

Вызов

void test( A* a )
{ 
   a->foo();
}

вызовет B::foo().

Один изящный эксперимент, который вы можете попробовать, - это скомпилировать B.dll с помощью header.h, а когда вы скомпилируете X.dll, инвертировать порядок методов вheader.h:

//header.h

class A
{
public:
    virtual void goo() = 0;
    virtual void foo() = 0;
};

В этом случае, хотя вы никогда не должны делать этого, тот же вызов test() в X.dll, вероятно, вызовет метод B::goo().Это потому, что X.dll предполагает наличие vftable в заголовке.Это неопределенное поведение, хотя;Я просто написал этот пример, чтобы сделать точку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...