C ++ поздняя привязка (динамическое связывание) [дубликат]

Невозможность связывания с соответствующими библиотеками / объектными файлами или компиляция файлов реализации

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

В разделе gcc вы должны указать все объектные файлы, которые должны быть связаны вместе в командной строке, или скомпилировать файлы реализации вместе.

g++ -o test objectFile1.o objectFile2.o -lLibraryName

Здесь libraryName - это просто имя библиотеки, без добавления к платформе. Так, например, в файлах библиотеки Linux обычно называют libfoo.so, но вы должны писать только -lfoo. В Windows этот же файл можно назвать foo.lib, но вы будете использовать тот же аргумент. Возможно, вам придется добавить каталог, в котором эти файлы можно найти, используя -L‹directory›. Обязательно не записывайте пробел после -l или -L.

Для XCode: добавьте пути поиска заголовка пользователя -> добавьте путь поиска библиотеки -> перетащите фактическую ссылку библиотеки в

В MSVS файлы, добавленные в проект, автоматически связывают их объектные файлы, и будет создан файл lib (в общем использовании). Чтобы использовать символы в отдельном проекте, вам нужно будет добавить файлы lib в параметры проекта. Это делается в разделе Linker свойств проекта в Input -> Additional Dependencies. (путь к файлу lib должен быть добавлен в Linker -> General -> Additional Library Directories). При использовании сторонней библиотеки, которая предоставляется с файлом lib, отказ в этом обычно приводит к ошибке.

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

В программировании Windows контрольный знак, который вы не связывали необходимая библиотека состоит в том, что имя неразрешенного символа начинается с __imp_. Посмотрите имя функции в документации, и она должна сказать, какую библиотеку вам нужно использовать. Например, MSDN помещает информацию в поле внизу каждой функции в разделе «Библиотека».

63
задан Andre Silva 25 November 2013 в 20:54
поделиться

11 ответов

Этот вопрос может вам помочь.

Динамическая отправка обычно относится к нескольким диспетчерам.

Рассмотрим приведенный ниже пример. Я надеюсь, что это может вам помочь.

    class Base2;
    class Derived2; //Derived2 class is child of Base2
class Base1 {
    public:
        virtual void function1 (Base2 *);
        virtual void function1 (Derived2 *);
}

class Derived1: public Base1 {
    public:
    //override.
    virtual void function1(Base2 *);
    virtual void function1(Derived2 *);
};

Рассмотрим случай ниже.

Derived1 * d = new Derived1;
Base2 * b = new Derived2;

//Now which function1 will be called.
d->function1(b);

Он назовет function1, взяв Base2* не Derived2*. Это связано с отсутствием динамической множественной отправки.

Позднее связывание является одним из механизмов реализации динамической отдельной отправки.

56
ответ дан Community 27 August 2018 в 05:29
поделиться

Достаточно достойный ответ на этот вопрос фактически включен в вопрос о позднем и раннем привязке к programers.stackexchange.com .

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

В C ++ у нас на самом деле нет поздней привязки, потому что известен тип (не обязательно конец иерархии наследования, но по крайней мере формальный базовый класс или интерфейс) , Но мы делаем динамическую отправку с помощью виртуальных методов и полиморфизма.

Лучший пример, который я могу предложить для позднего связывания, - это нетипизированный «объект» в Visual Basic. Среда выполнения выполняет весь тяжелый подъем для вас.

Dim obj

- initialize object then..
obj.DoSomething()

Компилятор фактически закодирует соответствующий контекст выполнения для среды выполнения для выполнения именованного поиска метода с именем DoSomething , и если они обнаружены с соответствующими параметрами соответствия, фактически выполните основной вызов. В действительности, что-то о типе объекта известно (он наследует от IDispatch и поддерживает GetIDsOfNames() и т. Д.). но в отношении языка тип переменной во время компиляции совершенно неизвестен, и он не знает, является ли DoSomething даже методом для любого obj на самом деле равно , пока время выполнения не достигнет точки выполнения.

Я не буду беспокоить демпинг виртуального интерфейса C ++ et'al, так как я уверен, вы уже знаете, что они выглядит как. Надеюсь, что язык C ++ просто не может этого сделать. Он строго типизирован. Он может (и делает, очевидно) динамическую отправку через функцию полиморфного виртуального метода.

56
ответ дан Community 27 August 2018 в 05:29
поделиться

Позвольте мне привести вам пример различий, потому что они НЕ совпадают. Да, динамическая отправка позволяет выбрать правильный метод, когда вы ссылаетесь на объект суперкласса, но эта магия очень специфична для этой иерархии классов, и вам нужно сделать некоторые объявления в базовом классе, чтобы заставить его работать (абстрактные методы заполните vtables, поскольку индекс метода в таблице не может меняться между конкретными типами). Таким образом, вы можете вызывать методы в Tabby, Lion и Tiger всеми с помощью указателя Cat Cat и даже иметь массивы кошек, заполненных львами и тиграми и Tabbys. Он знает, какие индексы относятся к этим методам в виртуальной таблице объекта во время компиляции (статическое / раннее связывание), хотя метод выбран во время выполнения (динамическая отправка ).

Теперь давайте реализуем массив, содержащий Lions, Tigers and Bears! ((Oh My!)). Предполагая, что у нас нет базового класса под названием Animal, в C ++ у вас будет большая работа, потому что компилятор не позволит вам выполнять динамическую отправку без общего базового класса. Индексы для vtables должны совпадать, и это невозможно сделать между нереализованными классами. Вам нужно иметь виртуальную таблицу, достаточно большую для хранения виртуальных методов всех классов в системе. Программисты на С ++ редко рассматривают это как ограничение, потому что вы были обучены мыслить определенным образом о дизайне классов. Я не говорю об этом лучше или хуже.

С поздним связыванием время выполнения позаботится об этом без общего базового класса. Обычно используется хэш-таблица, используемая для поиска методов в классах с использованием системы кэша, используемой в диспетчере. Где в C ++ компилятор знает все типы. На позднем языке сами объекты знают свой тип (его нетипичный, сами объекты точно знают, кто они в большинстве случаев). Это означает, что я могу иметь массивы нескольких типов объектов, если захочу (Львы, Тигры и Медведи). И вы можете реализовать пересылку и прототипирование сообщений (позволяет изменять поведение на один объект без изменения класса) и всевозможные другие вещи способами, которые намного более гибки и приводят к меньшему набросу кода, чем к языкам, которые не поддерживают позднюю привязку .

Вы когда-нибудь программировали на Android и использовали findViewById ()? Вы почти всегда заканчиваете вывод результата, чтобы получить правильный тип, и кастинг в основном лежит на компиляторе и отказывается от всей статической проверки подлинности типа, которая должна сделать статические языки выше. Разумеется, вместо этого вы можете найти findTextViewById (), findEditTextById () и миллион других, чтобы ваши типы возвращались, но это бросает полиморфизм из окна; возможно, всю основу ООП. Язык с поздним связыванием, вероятно, позволит вам просто индексировать идентификатор и рассматривать его как хеш-таблицу и не заботятся о том, что тип индексировался и не возвращался.

Вот еще один пример. Предположим, что у вас есть класс Lion, и его поведение по умолчанию состоит в том, чтобы съесть вас, когда вы его увидите. В C ++, если вы хотите иметь одного «обученного» льва, вам нужно создать новый подкласс. Прототипирование позволит вам просто изменить один или два метода этого конкретного Льва, которые необходимо изменить. Класс и тип не меняются. C ++ не может этого сделать. Это важно, поскольку, когда у вас есть новый «AfricanSpottedLion», который наследуется от Льва, вы также можете его обучать. Прототипирование не меняет структуру класса, поэтому его можно развернуть. Обычно эти языки обрабатывают проблемы, которые обычно требуют множественного наследования, или, возможно, множественное наследование - это то, как вы справляетесь с отсутствием прототипирования.

FYI, Objective-C - это C с добавлением сообщения SmallTalk, а SmallTalk - оригинальные ООП, и оба опоздали со всеми вышеперечисленными функциями. Поздно связанные языки могут быть немного медленнее с точки зрения микроуровня, но часто позволяют структурировать код таким образом, который более эффективен на макроуровне, и все это сводится к предпочтению.

2
ответ дан 2 revs 27 August 2018 в 05:29
поделиться

Учитывая, что словословное определение Wikipedia у меня возникло бы у соблазна классифицировать динамическую отправку как позднюю привязку C ++

struct Base {
    virtual void foo(); // Dynamic dispatch according to Wikipedia definition
    void bar();         // Static dispatch according to Wikipedia definition
};

Позднее связывание вместо этого, для Википедии, похоже, означает отправку указателя на член C ++

(this->*mptr)();

, где выбор того, что вызывается при вызове операции (а не только эта реализация), выполняется во время выполнения.

Однако в литературе на C ++ late binding обычно используется для чего Википедия вызывает динамическую отправку.

2
ответ дан 6502 27 August 2018 в 05:29
поделиться

Связывание относится к процессу связывания имени с операцией.

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

Dispatching относится к выбору реализация для операции после того, как вы определили, к какой операции относится имя.

диспетчерское управление для этого в соответствии с параметром match

http://en.wikipedia.org/ wiki / Dynamic_dispatch

надеюсь, что это поможет вам

5
ответ дан bhupinder 27 August 2018 в 05:29
поделиться

Сама ссылка link объясняет разницу:

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

и

При динамической отправке имя может быть связано с полиморфной операцией во время компиляции, но реализация не будет выбрана до времени выполнения (это как динамическая диспетчеризация работает на C ++). Однако последнее связывание подразумевает динамическую диспетчеризацию, поскольку вы не можете выбрать, какую реализацию полиморфной операции выбрать, пока не будет выбрана операция, на которую ссылается имя.

Но они в основном равны C ++ вы можете динамически отправлять виртуальные функции и vtables.

C ++ использует раннее связывание и предлагает динамическую и статическую отправку. Форма отправки по умолчанию является статической. Чтобы получить динамическую отправку, вы должны объявить метод виртуальным.

8
ответ дан deepmax 27 August 2018 в 05:29
поделиться

В C ++ оба dynamic dispatch и late binding совпадают. В принципе, значение одного объекта определяет кусок кода, вызываемый во время выполнения. В таких языках, как C ++ и динамическая диспетчеризация java, более конкретно динамическая разовая отправка, которая работает, как указано выше. В этом случае, поскольку привязка происходит во время выполнения, ее также называют late binding. Языки, подобные smalltalk, допускают динамическую множественную отправку, в которой во время выполнения выбирается метод времени выполнения, основанный на идентификаторах или значениях более чем одного объекта.

В C ++ у нас действительно нет позднего связывания, поскольку информация о типе известна , Таким образом, в контексте C ++ или Java динамическая отправка и поздняя привязка одинаковы. Фактическое / полностью позднее связывание, я думаю, в таких языках, как python, который основан на методе, а не на основе типа.

0
ответ дан jester 27 August 2018 в 05:29
поделиться

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

Существуют специальные функции для определения того, какой тип определенного объекта в определенное время. как instanceof в java, или if(typeid(b) == typeid(A))... в c ++.

0
ответ дан MeNa 27 August 2018 в 05:29
поделиться

В C ++ оба одинаковы.

В C ++ существует два типа привязки:

  • static binding & mdash; который выполняется во время компиляции.
  • dynamic binding & mdash; который выполняется во время выполнения.

Динамическое связывание, поскольку оно выполняется во время выполнения, также упоминается как late binding , а статическая привязка иногда называется раннее связывание .

Используя динамическое связывание, C ++ поддерживает runtime-полиморфизм через функции virtual (или указатели на функции ) и используя статическую привязку, все другие вызовы функций разрешены.

5
ответ дан Nawaz 27 August 2018 в 05:29
поделиться

Динамическая отправка - это то, что происходит, когда вы используете ключевое слово virtual в C ++. Так, например:

struct Base
{
    virtual int method1() { return 1; }
    virtual int method2() { return 2; } // not overridden
};

struct Derived : public Base
{
    virtual int method1() { return 3; }
}

int main()
{
    Base* b = new Derived;
    std::cout << b->method1() << std::endl;
}

выведет 3, потому что метод был динамически отправлен . Стандарт C ++ очень осторожен not , чтобы указать, как именно это происходит за кулисами, но каждый компилятор под солнцем делает это одинаково. Они создают таблицу указателей функций для каждого полиморфного типа (называемую виртуальной таблицей или vtable ), а при вызове виртуального метода «реальный» метод просматривается из vtable, и эта версия вызывается. Таким образом, вы можете визуализировать что-то вроде этого псевдокода:

struct BaseVTable
{
    int (*_method1) () = &Base::method1; // real function address
    int (*_method2) () = &Base::method2;
};

struct DerivedVTable
{  
    int (*method) () = &Derived::method1;
    int (*method2) () = &Base::method2; // not overridden
};

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


С другой стороны, мое понимание термина позднего связывания заключается в том, что указатель функции просматривается именем во время выполнения, из хэш-таблицы или чего-то подобного. Так делаются в Python, JavaScript и (если используется память) Objective-C. Это позволяет добавлять новые методы к классу во время выполнения , что не может быть непосредственно выполнено на C ++. Это особенно полезно для реализации таких вещей, как mixins. Однако недостатком является то, что просмотр во время выполнения, как правило, значительно медленнее, чем даже виртуальный вызов на C ++, и компилятор не может выполнять проверку типа компиляции для вновь добавленных методов.

1
ответ дан Tristan Brindle 27 August 2018 в 05:29
поделиться

Позднее связывание вызывает метод по имени во время выполнения. У вас действительно нет этого в c ++, за исключением импорта методов из DLL. Примером этого может быть: GetProcAddress ()

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

8
ответ дан Yochai Timmer 27 August 2018 в 05:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: