Имя: Пароль:
IT
 
С++ Виртуальные методы в конструкторе/деструкторе
0 Ненавижу 1С
 
гуру
31.03.11
16:25
верно ли в С++:

1. в деструкторе нельзя вызывать чисто виртуальные (абстрактные) методы
2. подозреваю что и в конструкторе тоже
3. в деструкторе вызов виртуального метода происходит как не виртуального
4. аналогично в конструкторе
1 holydel
 
31.03.11
16:53
1. в дестркторе кого? в деструкторе базового класса - можно - вызовется абстрактный метод базового класса(если есть реализация) в деструкторе производного класса - можно вызвать явно, через ::.

2. аналогично.

3. а как же иначе? мы вызываем один метод класса из другого метода класса (пусть деструктора). все вызовы методов класса будут невиртуальными.

4. аналогично.

[code]
#include <iostream>

class Abba
{
private:
   int a;

   void SetA(int a_)
   {
       std::cout<<"StA"<<std::endl;
       a = a_;
   }
public:
   int GetA()
   {
       return a;
   }

   virtual int VFunc() = 0;

   Abba()
   {
       std::cout<<"Abba ctr"<<std::endl;
       SetA(-1);
       VFunc();
   }

   ~Abba()
   {
       std::cout<<"Abba dtr"<<std::endl;
       SetA(1);
       VFunc();
   }
};

int Abba::VFunc()
{
   std::cout<<"Abba VFunc"<<std::endl;
   a = 3;
   return 5;
}

class Bitls : public Abba
{
public:
   virtual int VFunc()
   {
       std::cout<<"Bitls VFunc"<<std::endl;
       return Abba::VFunc()+1;
   }

   Bitls()
   {
       std::cout<<"Bitls ctr"<<std::endl;
       VFunc();
       Abba::VFunc();
   }

   ~Bitls()
   {
       std::cout<<"Bitls dtr"<<std::endl;
       VFunc();
       Abba::VFunc();
   }
};

int main(int argc, const char* argv[])
{
   {
       Bitls b;
   }
   int a;
   std::cin>>a;
   return 0;
}
[/code]
2 Rabbit
 
31.03.11
17:10
Я так скажу: ТВМ, или аналоги создаются до вызова тела конструктора и уничтожаются после вызова тела деструктора.
3 Ненавижу 1С
 
гуру
31.03.11
17:10
а как же это?
class A
{
public:
   virtual int Test1()=0;
   virtual int Test2(){return 0;}
   A()
   {
       //std::cout<<Test1(); закоментировано по причине ошибки компиляции
       std::cout<<Test2(); //выдает 0
   }
};

class B:public A
{
public:
   virtual int Test1(){return 1;}
   virtual int Test2(){return 1;}
};


   B* b = new B();
   delete b;
4 Fragster
 
гуру
31.03.11
17:13
(0) у меня 1ска что-то стала вылетать периодически с pure virtual function call - предположительно после включения управляемых блокировок
5 Rabbit
 
31.03.11
17:13
(3) а что такое экземпляр абстрактного класса?
6 Ненавижу 1С
 
гуру
31.03.11
17:15
(1) у вас нет абстрактного метода
(5) а где ты такое увидел?
7 Rabbit
 
31.03.11
17:16
(6) A()
  {
      //std::cout<<Test1(); закоментировано по причине ошибки компиляции
      std::cout<<Test2(); //выдает 0
  }
Это конструктор чего? И у компилятора наверно ключики какие-то есть.
8 Ненавижу 1С
 
гуру
31.03.11
17:17
(7) это конструктор абстрактного класса, но экземпляров абстрактного класса я не создавал
9 Rabbit
 
31.03.11
17:19
(8) Тебе их не дали создать.
10 Ненавижу 1С
 
гуру
31.03.11
17:19
(9) ну и я не оспариваю этот факт
11 Rabbit
 
31.03.11
17:21
(10) иначе тебе бы пришлось ответить на (5)
12 Ненавижу 1С
 
гуру
31.03.11
17:22
(11) вот казуар ты, экземпляров абстрактного класса быть не может
13 Rabbit
 
31.03.11
17:23
(12) >> 3. в деструкторе вызов виртуального метода происходит как не виртуального
4. аналогично в конструкторе

А это откуда?
14 Ненавижу 1С
 
гуру
31.03.11
17:24
(13) но деструктор то абстрактного базового класса все равно вызывается ведь
15 Sk0rp
 
31.03.11
17:36
(0) Давай я кратко теорию расскажу, а ты сам решай какой выбор есть у компилятора:

1. Виртуальные функции имеют смысл когда есть наследование.
2. Для вызова правильной виртуальной функции каждый производный класс пишет указатель на свой вариант переопределяемой функции в таблицу виртуальных функций.
3. При создании класса он конструируется так: сначала базовый класс, потом его производный, потом производный производного и т.д.
4. Разрушение идет строго в обратном порядке.

Из пункта 3 следствие, что на момент работы конструктора базового класса, информации о производных классах еще нет, соответственно знать какие там будут переопределены виртуальные функции нельзя. Значит в конструкторе можно вызвать виртуальные функции только этого класса или базового. Это может вызвать существенную неопределенность: при вызове функции в конструкторе вызывается одна, а после конструктора уже вызовется другая функция.
В деструкторе все аналогично: производный объект уже разрушен и указатель на таблицу виртуальных функция изменен - будет вызвана та еж функция, что вызвалась бы в конструторе, но не та, что вызывалась во время жизни объекта.
Поэтому в целях уменьшения неразберихи это обычно запрещется. Впрочем функцию по прежнему можно вызвать невиртуально (явно через 2 двоеточия указав класс из которого её взять)
16 Sk0rp
 
31.03.11
17:41
(3) Надо различать виртуальные и "чисто виртуальные" (pure virtual) функции. Первые обязательно имеют хоть какое-то тело в базовом классе и её хотя-бы теоритически можно вызвать. Чисто виртуальные задают интерфейс для производных классов. Они обязательно должны быть переопределены для возможности создать объект. И вызвать из можно не ранее, чем она определена.
Компилятор можно обмануть, например через явное приведения указателя, в этом случае получается исключение: pure virtual call
17 Rabbit
 
31.03.11
17:51
(15) На самом деле всё было нетак
Чтобы обнаруживать ошибки, программист должен иметь ум, которому доставляет удовольствие находить изъяны там, где, казалось, царят красота и совершенство. Фредерик Брукс-младший