timochka>>Теперь переименовываем файл Mylib2.dll в Mylib1.dll и снова запускаем. timochka>>Видим "Я класс MyClass2." - Но ведь мы ничего не пересобирали! Значит на лицо динамическое связывание. Balancer>Таки, ИМХО, это всё равно статическое связывание. Оно происходит при линковке программы, а не при её исполнении. DLL - это всего лишь продвинутая отложенная линковка. Хотя, могу и ошибаться. Но пример ещё не убедительный Dll это динамическая библиотека. Я могу загрузить ее по имени и получить указатель на функцию ПО ИМЕНИ ФУНКЦИИ. И огребу граблей при возове если не положу аргументы таким образом как хочет функция.
К сожалению, у меня нет под рукой VC++, сделай, плиз, ассемблерный листинг вызова виртуальной функции - тогда и будет всё ясно
Кстати, вот ещё такая фишка. Динамическое связывание возможно только при наличии пространства имён, включённого в код готовой программы. А это автоматически подразумевает возможность вызова функции по её имени, полученному во время исполнения программы.
А вот и не угадал. Все виртуальные функции класса нумеруются, а в классе заводится таблица виртуальных функций vtable. Там лежат указатели на РЕАЛИЗАЦИЮ данного метода в этом классе. И все вызовы виртуальных функций идут через таблицу. Т.е. класс тащит с собой указатели на собственные методы.
Т.е. невозможно вызвать метод по его символьному ИМЕНИ, но вполне можно вызвать если знаешь позицию метода в vtable. Именно так и работает с СОМ модулями писаными на С++ не объектные языки (ассемблер например).
Mishka> А что еще добавить - Рома не прав, но не в том, что летчиков, а в том, что динамическое связывание было и есть в С++, а уж в Джаве можно точно вызвать метод из любого объекта. >Но в C++ - приведите мне ассемблерный кусок, показывающий именно динамическое связывание - я поверю Да нет, бред это! Ну не умеет C++ работать с незнакомыми ему классами! Пусть у нас суперкласс не имеет нужной виртуальной функции. Тогда, чтобы её вызывать, как в постинге с примерами, что привёл timochka при добавлении её в субкласс, мы обязаны прописать её в суперкласс и
перекомпилить dll с суперклассом. И это - динамическое связывание?? Зачем нам тогда перекомпиляция?
Не иметь прототипа в базовом классе это все равно что не знать ее имени. Ты не обязан знать ее реализацию ( func() =0 как раз и обозначает абстрактную функцию) Но надо указать ее смещение в таблице виртуальных функций и типы аргументов + тип возвращаемого значения.
А на ассемблере будет конструкция типа call classInstance.vtable[XXX]
Может тебя Рома такой кусок убедит.
class IMyInterface
{
public:
virtual void WhoIam(void) =0;
};
class MyClass1 : public IMyInterface
{
public:
virtual void WhoIam(void) { MessageBox(0l, "Я класс MyClass1", "Info", MB_OK); };
};
class MyClass2 : public IMyInterface
{
public:
virtual void WhoIam(void) { MessageBox(0l, "Я класс MyClass2", "Info", MB_OK); };
};
class MyClass33 : public MyClass2
{
public:
virtual void WhoIam(void) { MessageBox(0l, "Я класс MyClass33", "Info", MB_OK); };
};
IMyInterface GetInterface(void)
{
IMyInterface *pIntance = 0l;
switch (clock() % 3) // часы как датчик случайных чисел. Криво но так проще.
{
case 0:
pIntance = new MyClass1();
break;
case 1:
pIntance = new MyClass2();
break;
case 2:
pIntance = new MyClass3();
break;
}
return *pInstance;
}
// И гдето в нашей проге делаем такую шутку for (int i = 0; i < 10; ++i)
{
GetInterface().WhoIam();
Sleep(100);
}
Это сообщение редактировалось 27.05.2003 в 16:41