Форум программистов, компьютерный форум CyberForum.ru

Позднее и раннее связывание - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 93, средняя оценка - 4.74
lex123456
0 / 0 / 0
Регистрация: 18.11.2009
Сообщений: 13
21.05.2011, 00:31     Позднее и раннее связывание #1
у меня проблема не могу разобратся с этим "приведите пример (без реализации методов) познего и раннего связывание" завтро здавать а мыслей ноль.
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ValeryLaptev
Эксперт C++
1005 / 784 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
21.05.2011, 12:18     Позднее и раннее связывание #2
Раннее связывание - на этапе компиляции. Позднее - при выполнении. Виртуальные функции для того и делаются.
Пример: указателю базового класса присваивается указатель производного класса и вызывается виртуальный метод.
lex123456
0 / 0 / 0
Регистрация: 18.11.2009
Сообщений: 13
03.06.2011, 04:11  [ТС]     Позднее и раннее связывание #3
пример привести можешь?
ValeryLaptev
Эксперт C++
1005 / 784 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
03.06.2011, 09:29     Позднее и раннее связывание #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Вот тебе материал - надергай из него:

Зачем нужны виртуальные функции
При наследовании часто бывает необходимо, чтобы поведение некоторых методов базового класса и классов-наследников отличались. Решение, на первый взгляд, очевидное: переопределить соответствующие методы в производном классе. Однако тут возникает одна проблема, которую лучше рассмотреть на простом примере (листинг 9.1).
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Листинг 9.1. Необходимость виртуальных функций
#include <iostream>
using namespace std;
class Base                                 // базовый класс
{  public:
    int f(const int &d)                    // метод базового класса
    { return 2*d; }
    int CallFunction(const int &d)         // предполагается
    { return f(d)+1;                       // вызов метода базового класса
    }
};
class Derived: public Base                 // производный класс
{  public:                                 // CallFunction наследуется
    int f(const int &d)                    // метод f переопределяется
    { return d*d; }
};
int main()
{   Base a;                                // объект базового класса
    cout << a.CallFunction(5)<< endl;      // получаем 11
    Derived b;                             // объект производного власса
    cout << b.CallFunction(5)<< endl;      // какой метод f вызывается?
    return 0;
}
В базовом классе определены два метода — f() и CallFunction(), — причем во втором методе вызывается первый. В классе-наследнике метод f() переопределен, а метод CallFunction() унаследован. Очевидно, метод f() переопределяется для того, чтобы объекты базового класса и класса-наследника вели себя по-разному. Объявляя объект b типа Derived, программист, естественно, ожидает получить результат 5 * 5 + 1 = 26 — для этого и переопределялся метод f(). Однако на экран, как и для объекта а типа Base, выводится число 11, которое очевидно вычисляется как 2 * 5 + 1 = 11. Несмотря на переопределение метода f() в классе-наследнике, в унаследованной функции CallFunction() вызывается «родная» функция f(), определенная в базовом классе!
Аналогичная проблема возникает и в несколько другом контексте: при подстановке ссылки или указателя на объект производного класса вместо ссылки или указателя на объект базового. Рассмотрим опять пример с часами и будильником (листинг 9.2).
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Листинг 9.2. Неожиданная работа принципа подстановки
class Clock               // базовый класс — часы
{ public:
    void print() const { cout << "Clock!" << endl; }
};
class Alarm: public Clock // производный класс — будильник
{ public:
    void print() const    // переопределенный метод
    { cout << "Alarm!" << endl; }
};
void settime(Clock &d)    // функция установки времени
{ d.print(); }            // предполагается вызов метода базового класса
//...
Clock W;                  // объект базового класса
settime(W);               // выводится "Clock"
Alarm U;                  // объект производного класса
settime(U);               // ссылка на производный вместо базового 
Clock *c1 = &W;           // адрес объекта базового класса
c1->print();              // вызов базового метода 
c1 = &U;                  // адрес объекта производного типа вместо базового
c1->print();              // какой метод вызываетя, базовый или производный?
Опять в классе-наследнике переопределен метод для того, чтобы обеспечить различное поведение объектов базового и производного классов. Однако и при передаче параметра по ссылке базового класса в функцию settime(), и при явном вызове метода print() через указатель базового класса наблюдается одна и та же картина: всегда вызывается метод базового класса, хотя намерения программиста состоят в том, чтобы вызвать метод производного.
Для того чтобы разобраться в ситуации, необходимо уяснить, что такое связывание. Связывание — это сопоставление вызова функции с телом. В приведенных ранее примерах связывание выполняется на этапе трансляции (до запуска) программы. Такое связывание обычно называют ранним, или статическим.

При трансляции класса Base (см. листинг 9.1) компилятор ничего не знает о классах-наследниках , поэтому он не может предполагать, что метод f() будет переопределен в классе Derived. Его естественное поведение — «прочно» связать вызов f() с телом метода класса Base. Аналогично при трансляции функции settime() компилятору ничего не известно о типе реально передаваемого объекта во время выполнения программы. Поэтому вызов метода print() связывается с телом метода базового класса Clock, как и определено в заголовке функции settime(). Точно так же указатель на базовый класс «прочно» связывается с методом базового класса во время трансляции.
Конечно, при вызове метода по указателю в данном конкретном случае мы можем вызвать метод производного класса, задав явное преобразование указателя:
C++
1
static_cast<Alarm*>(c1)->print();
Или так:
C++
1
((Alarm *)c1)->print();                // "лишние" скобки нужны!
Однако для функции settime() и метода CallFunction() это сделать невозможно — нам необходимо именно разное поведение в зависимости от типа объекта. Да и с указателем не все так просто: если такой вызов прописан внутри функции, которая принимает этот указатель как параметр (например, settime(Clock *c1)), то мы имеем те же проблемы.

Определение виртуальных функций
Получается, что в С++ должен существовать механизм, с помощью которого можно узнать тип объекта во время выполнения программы. Такой механизм в С++ есть и он, как уже отмечалось, называется динамической идентификацией типов (RTTI). Однако в ситуациях, подобных описанным, применяется другой, более «сильный» и элегантный механизм С++ — механизм виртуальных функций (см. п. 10.3 в [1]).
Чтобы добиться разного поведения в зависимости от типа, необходимо объявить функцию-метод виртуальной; в С++ это делается с помощью ключевого слова virtual. Таким образом, в листинге 9.1 объявление метода f() в базовом и производном классе должно быть таким:
C++
1
2
3
4
virtual int f(const int &d)                // в базовом классе
            { return 2*d; }
virtual int f(const int &d)                // в производном классе
            { return d*d; }
После этого для объектов базового и производного классов мы получаем разные результаты: 11 и 26.
Аналогично в листинге 9.2 объявление метода print() тоже должно начинаться со слова virtual:
C++
1
2
3
4
virtual    void print() const              // в базовом классе
{ cout << "Clock!" << endl; }
virtual    void print() const              // в производном классе
{ cout << "Alarm!" << endl; }
После этого вызов settime() с параметром базового класса обеспечит нам вывод на экран слова «Clock», а с параметром производного класса — слова «Alarm». И при вызове по указателю наблюдается та же картина.

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

Для виртуальных функций обеспечивается не статическое, а динамическое (позднее, отложенное) связывание, которое реализуется во время выполнения программы. Естественно, это влечет за собой некоторые накладные расходы, однако на них можно не обращать внимания, так как обеспечивается динамический полиморфизм. Александреску в [20] указывает, что в С++ реализованы два типа полиморфизма:
- статический полиморфизм, или полиморфизм времени компиляции (compile-time polymorphism), осуществляется за счет перегрузки и шаблонов функций;
- динамический полиморфизм, или полиморфизм времени выполнения (run-time polymorphism), реализуется виртуальными функциями.


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

Правила описания и использования виртуальных функций-методов следующие:
1. Виртуальная функция может быть только методом класса.
2. Любую перегружаемую операцию-метод класса можно сделать виртуальной, например, операцию присваивания или операцию преобразования типа.
3. Виртуальная функция, как и сама виртуальность, наследуется.
4. Виртуальная функция может быть константной.
5. Если в базовом классе определена виртуальная функция, то метод производного класса с такими же именем и прототипом (включая тип возвращаемого значения и константность метода) автоматически является виртуальным (слово virtual указывать необязательно) и замещает функцию-метод базового класса.
6. Конструкторы не могут быть виртуальными.
7. Статические методы не могут быть виртуальными.
8. Деструкторы могут (чаще — должны) быть виртуальными — это гарантирует корректный возврат памяти через указатель базового класса.
lex123456
0 / 0 / 0
Регистрация: 18.11.2009
Сообщений: 13
03.06.2011, 13:52  [ТС]     Позднее и раннее связывание #5
ValeryLaptev, помоги с таким вопросом

приведите пример демонстрирующий необходимость и все случаи использование конструктора копирования.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
 using namespace std;
 #include <stdlib.h>
 class cls
 { char *str;
     int dl;
     
   public:
     cls (); 
     cls(cls &); 
     ~cls(); 
 
 };
 cls::cls ()
 { dl=10;
    str=new char[dl];
 }
 cls::cls(cls & obj1) 
 { dl=obj1.dl; 
    str=new char[dl]; 
    strcpy(str,obj1.str); 
 }
 cls::~cls()
 { delete [] str;
    cout<<"деструктор"<<endl;
 }
 void fun(cls obj1)
 {
уже засыпаю

 Комментарий модератора 
Используйте теги форматирования кода!
Александр199321
0 / 0 / 0
Регистрация: 25.11.2014
Сообщений: 15
26.11.2014, 11:47     Позднее и раннее связывание #6
Вопрос 7


Когда происходит динамическое связывания
ответ а во время связоования
ответ B во воремя инкапсуляции
ответ С во время камиляции
ответ D Во время конструирования
ответ E Во время выполнения
какой тут правильный ответ это с теста вопрос

и вопрос 5
Какова роль символа ":" в коде class int arrayRc: public intArray{};
Вот ответьте на эти вопросы пожалуйста

Спасибо вам большое

Добавлено через 2 минуты
Это вопросы с теста тема перегрузка операторов мне надо завтра сдать поможите ребята ответы написать
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.11.2014, 11:50     Позднее и раннее связывание
Еще ссылки по теме:

Связывание классов C++
Проверить, содержится ли последнее введенное число среди введенных раннее элементов массива C++
C++ Найти в массиве сведений о компьютерах такой, который был выпущен позднее других

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11841 / 6820 / 771
Регистрация: 27.09.2012
Сообщений: 16,911
Записей в блоге: 2
Завершенные тесты: 1
26.11.2014, 11:50     Позднее и раннее связывание #7
Цитата Сообщение от Александр199321 Посмотреть сообщение
Когда происходит динамическое связывания
сначала читать поучитесь!
Цитата Сообщение от ValeryLaptev Посмотреть сообщение
Раннее связывание - на этапе компиляции. Позднее - при выполнении.
Добавлено через 2 минуты
Цитата Сообщение от Александр199321 Посмотреть сообщение
Какова роль символа ":" в коде class int arrayRc: public intArray{};
любой учебник! Глава - наследование
Yandex
Объявления
26.11.2014, 11:50     Позднее и раннее связывание
Ответ Создать тему
Опции темы

Текущее время: 02:20. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru