Модераторы: bsa
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Виртуальные функции 
:(
    Опции темы
Алексей
Дата 24.2.2009, 09:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 19.6.2006

Репутация: нет
Всего: нет



То ли я неправильно понял теорию, то ли еще что...

Код

class A{
public:
    virtual int fa();
};

class B: public A{
public:
    virtual int fb();
};

int A::fa(){
return 1;
}

int B::fb(){
return 2;
}

int main(){
   A *a;
   B b;
   a = &b;

}


Почему я не могу теперь обратиться к  B::fb() через 
Код

a->fb()


ведь мой указатель, если я правильно понимаю, сейчас должен указывать на таблицу виртуальных функция класса B. А в ней, благодаря наследованию должно быть 2 функции A::fa() и B::fb(). Или я что-то неправильно понял?
PM MAIL   Вверх
vinter
Дата 24.2.2009, 10:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 8
Всего: 56





--------------------
Мой блог
PM MAIL WWW   Вверх
Алексей
Дата 24.2.2009, 10:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 19.6.2006

Репутация: нет
Всего: нет



Да, я как раз и прочитал эту статью. Вот теперь перешел к практики и не понимаю, что я делаю не так.
PM MAIL   Вверх
azesmcar
Дата 24.2.2009, 10:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата

Почему я не могу теперь обратиться к  B::fb() через 

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

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

Например

Код

class A
{
public:
   void f()
   {
      cout << "A" << std::endl;
   }
}

class B : public A
{
public:
   void f()
   {
      cout << "B" << std::endl;
   }
}

int main()
{
    A* p = new B;
    p->f(); //выводится А потому что функция f не виртуальная и вызывается по типу указателя p (A)
    return 0;
}



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

Название твоих функций разные, и тут нет никакого полиморфизма. Если не перекрывать функции - виртуальность функций теряет смысл.

Это сообщение отредактировал(а) azesmcar - 24.2.2009, 10:17
PM   Вверх
Алексей
Дата 24.2.2009, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 19.6.2006

Репутация: нет
Всего: нет



А, то есть виртуальная функция обязана быть переопределена? smile 

Теперь яснее, но все равно непонятна фраза в вышеупомянутой статье:

Код

В самом начале своей работы он устанавливает указатель таблицы виртуальных функций. 
Для нашего примера конструктор Vbase() установит его на таблицу из 2 элементов. 
Первый – содержит указатель на Vbase::foo, а второй - на Vbase::bar(). 
Далее вызовется конструктор V() и переустановит указатель на другую таблицу, 
которая уже содержит 3 элемента: V::foo(), Vbase::bar(), V::alpha().
 

Сами классы:
Код

class Vbase
{
    virtual void foo();
    virtual void bar();
    void do()
    {
        foo();
    }
    int v;
}

class V : public Vbase
{
    virtual void foo();
    virtual void alpha();
}


Я думал, что раз вторая таблица "содержит 3 элемента: V::foo(), Vbase::bar(), V::alpha()", то почему бы не обратиться к любому виртуальному методу, даже не объявленному в Vbase. В данном случае это V::alpha()



Это сообщение отредактировал(а) Алексей - 24.2.2009, 10:34
PM MAIL   Вверх
vinter
Дата 24.2.2009, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 8
Всего: 56



Цитата(Алексей @  24.2.2009,  11:32 Найти цитируемый пост)
А, то есть виртуальная функция обязана быть переопределена? 

чистая виртуальна - да(если конечно нужен не абстрактный потомок)
Цитата(Алексей @  24.2.2009,  11:32 Найти цитируемый пост)
Я думал, что раз вторая таблица "содержит 3 элемента: V::foo(), Vbase::bar(), V::alpha()", то почему бы не обратиться к любому виртуальному методу, даже не объявленному в Vbase. В данном случае это V::alpha()

Указатель на отца "знает" смещения своих виртуальных ф-ий в vtable, он ничего не знает о новой ф-ии потомка, а значит и не знает смещения ее в таблице.



--------------------
Мой блог
PM MAIL WWW   Вверх
Алексей
Дата 24.2.2009, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 112
Регистрация: 19.6.2006

Репутация: нет
Всего: нет



А, т.е. указатель отца смотрит смещения в своей таблице виртуальных функций и вызывает аналогичные функции из vtable реально созданного потомка, так? smile 
PM MAIL   Вверх
azesmcar
Дата 24.2.2009, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 52
Всего: 211



Цитата

А, то есть виртуальная функция обязана быть переопределена?


Ну не то чтобы обязана, просто без этого она бессмысленна. В конце концов ее кто-то должен переопределить.

Цитата

В самом начале своей работы он устанавливает указатель таблицы виртуальных функций. 
Для нашего примера конструктор Vbase() установит его на таблицу из 2 элементов. 
Первый – содержит указатель на Vbase::foo, а второй - на Vbase::bar(). 
Далее вызовется конструктор V() и переустановит указатель на другую таблицу, 
которая уже содержит 3 элемента: V::foo(), Vbase::bar(), V::alpha().


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

Код

Я думал, что раз вторая таблица "содержит 3 элемента: V::foo(), Vbase::bar(), V::alpha()", то почему бы не обратиться к любому виртуальному методу, даже не объявленному в Vbase. В данном случае это V::alpha()


нет, тут просто в классе потомке добавлена функция alpha, которую можно переопределить в потомках класса V. т.е. эта функция недоступна по указателю vBase

приведу пример чтобы тебе было легче понять что такое полиморфизм и зачем он. Например у нас есть класс человек (human), наследуем от него пару классов (man, woman). Рождаются они одинаково, растут тоже, но мыслят по разному...

Код

class human
{
public:
   virtual int logic() = 0;

   void born() {
       //родиться
   }

   void grow() {
       //расти
   }
}

class woman: public human
{
public:
   virtual int logic() {
      return rand() % INT_MAX;
   }
}

class man: public human
{
public:
   virtual int logic() {
      //очень сложные операции
      return rand() % 2;
   }
}


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

Добавлено @ 11:24
надеюсь мою шутку не рассмотрят как половую дискриминацию )))

Это сообщение отредактировал(а) azesmcar - 24.2.2009, 11:25
PM   Вверх
jonie
Дата 24.2.2009, 21:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 6
Всего: 118



http://habrahabr.ru/blogs/cpp/51229/
тут тоже расписано все довольно подробно...


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0517 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.