Подтвердить что ты не робот

Почему ld-компоновщик допускает несколько определений классов с теми же методами?

Рассмотрим этот файл first.cpp, содержащий определение класса и использующий:

#include <iostream>

struct Foo
{
    Foo(){ std::cout << "Foo()" << std::endl; }
    ~Foo(){ std::cout << "~Foo()" << std::endl; }
};

int main(){
    Foo f;
    return 0;
}

и другой, second.cpp, содержащий определение конфликтующего класса:

#include <iostream>

struct Foo
{
    Foo();
    ~Foo();
};

Foo::~Foo(){ std::cout << "wrong ~Foo()" << std::endl; }

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

Я скомпилировал эти команды:

$ g++ -c second.cpp -o second
$ g++ second first.cpp -o first

Переупорядочение аргументов второму вызову g++ не изменяет результат.

И когда выполняется first, это будет выход:

$ ./first
Foo()
wrong ~Foo()

Почему компоновщик допускает методы дублирования класса? Если это разрешено, почему печатается wrong ~Foo()?

4b9b3361

Ответ 1

Опять же, Undefined Поведение. Ваша программа имеет несколько определений для деструктора Foo, что означает, что оно нарушает ODR. Программа неправильная, и все может случиться.

Почему компоновщик не забирает его? Когда функция определена внутри определения класса, она неявно inline. Компиляторы обычно отмечают эти функции как "слабые символы". Затем компоновщик получает все единицы перевода и пытается разрешить символы. Слабые символы будут удалены компоновщиком, если необходимо (т.е. Если символ уже определен где-то в другом месте).

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


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

Поскольку все (но не более одного) являются слабыми символами (т.е. inline)

Почему в этом случае печатается неправильная ~ Foo()?

Поскольку вызов не был вложен, а компоновщик сбросил слабый символ