Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Полиморфизм и позднее связывание


Автор: Morel 23.8.2004, 09:09
Понять одну вещь никак не могу.
Код

class Device
{
  ...
 public:
 virtual Message TranslateMessage()=0;
  ...
}

class Pshaiba : public Device
{
  ...
 public:
 Message TranslateMessage();
}

Pshaiba  p(2,2,2,2);
Pshaiba  *p1;
p1= new Pshaiba (1,1,1,1);
// или так p1=&p;
p1->TranslateMessage(); //вызов из Device, что нафиг не надо!
p.TranslateMessage();



При раннем связывании все нормально вызывается TranslateMessage() из класса Pshaiba. А вот при позднем из Device. Почему так происходит?

Автор: Конструктор 23.8.2004, 09:15
Хм интересно как TranslateMessage вызывается из Device, если она там чисто-виртуальная функция?

Автор: Morel 23.8.2004, 09:36
Ну вот так и вызывается:

Pure virtual function called

Я и спрашиваю почему она оттуда вызывается, а не из Pshaiba.

Автор: gray_k 23.8.2004, 09:52
А как ты определил, что вызывается из Device? Она там у тебя объявлена нулевой, а значит реализации иметь не может. Мне кажется ты чего-то путаешь.

Автор: Конструктор 23.8.2004, 09:54
Вот я написал у себя:

Код

#include <stdio.h>
#include <conio.h>

class Device
{
   public:
   virtual int TranslateMessage() = 0;
};

class Pshaiba: public Device
{
   public:
   virtual int TranslateMessage()
   {
       puts ("Translate message");
       return -1;
   };
};

int main()
{
   Pshaiba p;
   Pshaiba * p1;
   p1 = new Pshaiba();

   clrscr();

   p1->TranslateMessage();
   p.TranslateMessage();

   getch();

   return 1;
}


У меня оба раза выводится TranslateMessage. (BC 3.1)
Попробуй Options->Compiler->C++ Options->C++ Virtual tables->[X] Smart

Автор: Vyacheslav 23.8.2004, 10:37
Может она из конструктора вызывается?

Автор: 3,14 23.8.2004, 10:52
Дык код правильно работает biggrin.gif В чём соль виртуальных ф-ий?
Код

Device *p = new Pshaiba();
p->TranslateMessage();

Выведет Translate message

Автор: Morel 24.8.2004, 09:15
Это я напутал с конструктором Pshaiba. В нем вызывал
Код
Device::Device(id,numinput,numoutput,numdatchik);

Получилось, что вызывались два конструктора Device, по умаолчанию и мой с параметрами. Сделал инициализацию отдельной функцией в Device
Код
 init(id,numinput,numoutput,numdatchik);

Все заработало.
Вопрос теперь чисто теоретический. Почему p.TranslateMessage() работал правильно?

Автор: 3,14 24.8.2004, 09:59
Он и должен работать правильно, пер-ая p имеет тип Pshaiba и, следовательно, вызывает TranslateMessage описанный в Pshaiba

Автор: Vyacheslav 24.8.2004, 12:04
ВСе таки надо поставить точки над i smile.gif
Сообщение
Pure virtual function called
Можно получить только в одном случае : вызвать виртуальную функцию в теле конструктора производного класса.
Это имело место или нет ?

Автор: lynx_916 24.8.2004, 22:19
Цитата(Vyacheslav @ 24.8.2004, 11:04)
вызвать виртуальную

поправочка, чисто виртуальную, а это большая разницца. wink.gif

Автор: Morel 25.8.2004, 09:17
2: 3,14
Цитата
пер-ая p имеет тип Pshaiba

А p1 другой что ли?

Вот как это происходит.

Код

#include <stdio.h>

class Device
{
  protected:
  int id;
  public:
  Device::Device();
  Device::Device(int);
  init(int);
  virtual void TranslateMessage()=0;
};

class Pshaiba : public Device
{
 public:
 Pshaiba();
 Pshaiba(int);
 void TranslateMessage();
};

Device::Device()
{

}

Device::Device(int t)
{
 id=t;
}


Device::init(int i)
{
 id=i;
}

void Device::TranslateMessage()
{
 printf ("Dev=%d",id);
}

void Pshaiba::TranslateMessage()
{
 printf ("Psh=%d",id);
}

Pshaiba::Pshaiba()
{

}

Pshaiba::Pshaiba(int i)
{
//init(i);
Device::Device(i);

}


void main ()
{
 Pshaiba p(1);
 Pshaiba *p1;

 p1= new Pshaiba(2);

 p1->TranslateMessage();             //Pure virtual function called

 p.TranslateMessage();

}


Если в конструкторе Pshaiba вызвать init(), то все нормально.

Автор: Borisff2003 25.8.2004, 09:29
Сделал твой код он прекрасно делается без всякого init
И такой вот делается
Код

class Device
{

public:
virtual void TranslateMessage()=0;

};

class Pshaiba : public Device
{

public:
 virtual void TranslateMessage();
};

void Pshaiba::TranslateMessage()
{

};

int main ()
{
Pshaiba p;
Device *p1;

p1= new Pshaiba();

p1->TranslateMessage();            
p.TranslateMessage();
return 0;
}



Автор: Morel 25.8.2004, 09:45
Странно у меня стабильно вылетает в BC 3.1, именно на строке
p1->TranslateMessage();.

Твой код понятно что будет работать. Я же говорил, что моя проблемма в конструкторах.

Автор: Vyacheslav 25.8.2004, 10:03
Прваивильно будет так
Код

Pshaiba::Pshaiba(int i):Device(i)
{

}


Автор: Vyacheslav 25.8.2004, 10:23
Цитата(lynx_916 @ 24.8.2004, 22:19)
Цитата(Vyacheslav @ 24.8.2004, )
вызвать виртуальную

поправочка, чисто виртуальную, а это большая разницца. wink.gif

Я имел в виду следущее
Код

class  Device
{
public:
Device(int i){init(i);}
Device(){}
virtual void TranslateMessage() = 0;
void init(int){ TranslateMessage();}
};

class Pshaiba : public Device
{

public:
Pshaiba(){  }
Pshaiba(int i):Device(i){  }
void TranslateMessage(){ std::cout << "Pshaiba";}
};

int main(int argc, char* argv[])
{
 Pshaiba p;
 Device* d = &p;
 d->init(1);   //  Ok   "Pshaiba"

 Pshaiba p1(1); //Error - вызов чистой виртуальной функции
}



Автор: Конструктор 25.8.2004, 13:07
Код

Device(int i){init(i);}
virtual void TranslateMessage() = 0;
void init(int){ TranslateMessage();}


ИМХО какой-то изврат, который все же работает как и должен, т.е. пытается вызывать чисто-виртульную ф-цию.

Автор: Borisff2003 25.8.2004, 13:13
Morel
ВЕСЬ Приведенный тобой код работает в VC6.

А кстати, можно ли вызывать виртуальные функции из конструктора?

Автор: 3,14 25.8.2004, 14:12
А после компиляции gcc при запуске ошибку кидает

Автор: Vyacheslav 25.8.2004, 16:56
Виртуальные функции вызывать из конструктора можно. Только нужно учитывать определенные особенности при вызове. Формально при вызове из конструктора она ведет себя как невиртуальная

Автор: Borisff2003 26.8.2004, 05:21
Цитата

Виртуальные функции вызывать из конструктора можно. Только нужно учитывать определенные особенности при вызове. Формально при вызове из конструктора она ведет себя как невиртуальная

Что мы и имеем tounge.gif

Автор: Vyacheslav 26.8.2004, 09:07
Кстати на заметку. В С++Builder VCL-ные классы(т.е. те которые являются производными от TObject) ведут себя иначе, нарушая стандарт. При вызове виртуальной функции в конструкторе, она вызывается именно как виртуальная. В результата в принципе возможно переопределять тело базового конструктора smile.gif
Код

class TBaseClass : public TObject
{
public:
    TBaseClass() { BaseConstuctorBody(); }
    virtual void BaseConstuctorBody(){ std::cout << "TBaseClass"; }
};

class TDerivedClass : public TObject
{
public:
    TDerivedClass() :TBaseClass(){ }
    //переопределяем тело базового конструктора  :)
    virtual void BaseConstuctorBody(){std::cout << "DerivedClass"; };
};

Причем эта особенность имеется толькло у VCL-классов. Для обычных все работает по стандарту

Автор: Morel 26.8.2004, 09:15
Всем спасибо вроде разобрался.
Отдельное спасибо за Pshaiba::Pshaiba(int i):Device(i).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)