Что означает clang's-Wweak-vtables?


Я в принципе не понимаю из Clang -Wweak-vtables. Вот что я наблюдал до сих пор:

случае один: (триггеры предупреждение)

class A {
    public:
    virtual ~A(){}        
};

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

случае два: (не вызывает предупреждение)

class A {
    public:
    virtual ~A(){}        
};   

int main(){}

три кнопки: (не вызывает предупреждение)

class A {
    public:
    virtual ~A();

};

A::~A(){}

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

случае четыре: (триггеры предупреждение)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}        
};    

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

случае пять: (не вызывает внимание)

class A {
    public:
    virtual ~A(){}
    virtual void fun();      
};    

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

случае шесть: (не вызывает предупреждение)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}
};    

class B : public A {};

int main(){}

Дело номер семь: (не вызывает предупреждение)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}
};    

class B : public A {
    public:
    virtual void fun(){}
};

int main(){}

точное предупреждение

warning: 'A' has no out-of-line virtual method definitions; its vtable 
will be emitted in every translation unit [-Wweak-vtables]

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

вопросы:

  1. почему это проблема?
  2. почему это исправляется путем объявления виртуальной функции? (Предупреждение говорит о определения)
  3. почему предупреждение не возникает, когда я не производный от класса?
  4. почему предупреждение не появляется, когда производный класс не имеет виртуального деструктора?
1 52

1 ответ:

если все класса virtual методы встроены, компилятор не может выбрать единицу перевода, в которой можно разместить одну общую копию vtable - вместо этого копия vtable должна быть помещена в каждый объектный файл, который в ней нуждается. На многих платформах компоновщик может унифицировать эти несколько копий, либо отбрасывая повторяющиеся определения, либо сопоставляя все ссылки на одну копию, поэтому это только предупреждение.

осуществляет из-за линии позволяет компилятору выбрать модуль преобразования, реализующий этот метод out-of-line в качестве "дома" для сведений о реализации класса, и помещает одну общую копию таблицы vtable в ту же единицу преобразования. Если несколько методов находятся вне строки, компилятор может сделать произвольный выбор метода, если этот выбор определяется только объявлением класса; например, GCC выбирает первый нестрочный метод в порядке объявления.

если вы не переопределить любой метод класса,virtual ключевое слово не имеет заметного эффекта, поэтому компилятор не должен выдавать vtable для класса. Если вы не производны от A, или если вы не можете объявить деструктор производного класса virtual, В и так Aтаблица vtable опущена. Если объявить дополнительные строки virtual метод для подавления предупреждения, а также сделать что-то, что переопределяет метод в A реализация невстроенные virtual (и его сопроводительная копия таблицы vtable) должна быть предоставлена в связанной единице перевода, иначе связывание не удастся, потому что отсутствует таблица vtable.