Страница 1 из 3

Каким образом выбирается версия функции, принимающей указатель на полиморфный класс?

Добавлено: 06 янв 2016, 11:19
Сионист

Код: Выделить всё

class A
{
 public:
  virtual void m()=0;
};

class B : public A
{
 public:
  virtual void m()
  {
  }
};

class D : public B
{
 public:
  virtual void m()
  {
  }
};

class C : public A
{
 public:
  virtual void m()
  {
  }
};

class E : public C
{
 public:
  virtual void m()
  {
  }
};

void f(A *a)
{
}

void f(B *b)
{
}

void f(C *c)
{
}

int main ()
{
 A *p;
 p=new B;
 f(p);
 delete p;
 p=new C;
 f(p);
 delete p;
 p=new D;
 f(p);
 delete p;
 p=new E;
 f(p);
 delete p;
 return 0;
}
Каким образом здесь выбирается версия функции в каждом случае вызова?

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 13:58
Romeo
Я три раза перечитал твой пост, поправил там кучу опечаток в коде и самом топике, и, в конце-концов, пришёл к выводу, что тебя расстраивает тишина на форуме, и ты подобными темами просто пытаешься расшевелить людей, ответ же на вопрос тебе совсем не интересует. По другому я не могу объяснить такую кучу опечаток. Это просто наплевательское отношение к читателям. Неужели трудно хотя бы один раз перечитать то, что запостил? Или это сделано намеренно, и это такой грубый троллинг?

По теме: в данном случае функция будет выбрана по наибольшему соответствию типа. Иными словами, во всех случаях будет вызвана f(A*).

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

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 14:46
Сионист
Компилятор ни одной очепятки не заметил.
По теме: в данном случае функция будет выбрана по по наибольшему соответствию типа. Иными словами, во всех случаях будет вызвана f(A*).
Страуструп прямо пишет, что выбирается функция, максимально соответствующая фактическому типу. Если есть версия, принимающая фактический тип, то вызывается она, иначе - версия, принимающая указатель на ближайшего предка. В данном случае

Код: Выделить всё

class A
{
 public:
  virtual void m()=0;
};

class B : public A
{
 public:
  virtual void m()
  {
  }
};

class D : public B
{
 public:
  virtual void m()
  {
  }
};

class E : public C
{
 public:
  virtual void m()
  {
  }
};

void f(A *a)
{
}

void f(B *b)
{
}

void f(C *c)
{
}

int main ()
{
 A *p;
 p=new B;
 f(p); //Вызывается версия, принимающая B* 
 delete p;
 p=new C; 
 f(p); //Вызывается версия, принимающая C* 
 delete p;
 p=new D; 
 f(p); //Вызывается версия, принимающая B* 
 delete p;
 p=new E;
 f(p); //Вызывается версия, принимающая C* 
 delete p;
 return 0;
}
. А вот каким образом это делается? Если

Код: Выделить всё

class A
{
 public:
  virtual void m()=0;
};

class B : public A
{
 public:
  virtual void m()
  {
  }
};

class D : public B
{
 public:
  virtual void m()
  {
  }
};

class E : public C
{
 public:
  virtual void m()
  {
  }
};

void f(B b)
{
}

void f(C c)
{
}

int main ()
{
 B b;
 C c;
 D d;
 E e;
 f(b);
 f(c);
 f(d);
 f(e);
 return 0;
}
, то фактический тип известен на этапе компиляции. А в случае указателя?

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 14:51
Romeo
Вместо public там было везде написано publuc. Вместо virtual - firtual. Интересно, как это компилилось. Может компилятор специальный? :)

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 14:53
Absurd
пришёл к выводу, что тебя расстраивает тишина на форуме, и ты подобными темами просто пытаешься расшевелить людей, ответ же на вопрос тебе совсем не интересует.
Ну не знаю, если погуглить "taras atavin", можно много чего интересного найти.

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 15:00
Romeo
Absurd писал(а):Ну не знаю, если погуглить "taras atavin", можно много чего интересного найти.
Первая же ссылка ведёт на некий форумный профиль с такой же авой, как и у нашего друга. Это что, один и тот же человек? :)

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 15:03
Сионист
А в чём смысл таких функций, если полиморфизм будет работать благодаря виртуальным методам? Как раз одной функции достаточно.
А ни кто не говорил, что эти функции вообще будут обращаться к методам. Может они обращаются только к переменным-членам?

Код: Выделить всё

class A
{
 public:
  virtual void m()=0;
};

class B : public A
{
 public:
  int x;
  virtual void m()
  {
  }
};

class C : public A
{
 public:
  double y;
  virtual void m()
  {
  }
};

class D : public B
{
 public:
  char c;
  virtual void m()
  {
  }
};

class E : public C
{
 public:
 bool f 
  virtual void m()
  {
  }
};

void f(A *a)
{

}

void f(B *b)
{
 x=2; 
 if (dynamic_cast<D*>b)
 {
  (dynamic_cast<B*>a)->с='f';
 }
}

void f(C *c)
{
 y*=2.4;
 if (dynamic_cast<D*>b)
 {
  (dynamic_cast<B*>a)->f=!(dynamic_cast<B*>a)->f;
 }
}

int main ()
{
 A *p;
 p=new B;
 f(p);
 delete p;
 p=new C;
 f(p);
 delete p;
 p=new D;
 f(p);
 delete p;
 p=new E;
 f(p);
 delete p;
 return 0;
}
.
Вместо public там было везде написано publuc. Вместо virtual - firtual. Интересно, как это компилилось. Может компилятор специальный?
А куда при исправлении делся класс C?

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 15:09
Absurd
Первая же ссылка ведёт на некий форумный профиль с такой же авой, как и у нашего друга.
Я случайно напоролся на этот профиль когда значение "Эй Си" искал.

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 16:21
Romeo
Сионист, так код не пишут: касты не для этого созданы.

По поводу указателя - я уже сказал, как всё будет работать. Всегда будет вызываться f(A*), так как ты сам делаешь кастинг к указателю этого типа при присваивании.

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла

Добавлено: 06 янв 2016, 16:33
Сионист
Объекты могут поставляться сторонним кодом, при этом может отсутствовать возможность переписать методы, но могут требоваться различные действия в зависимости от фактического класса каждого объекта. Предположим, под A скрывается TEvent, версии функции - это обработчики, а метод вызывается в том случае, если приложение обрабатывает данное событие. Факт наличия версии, принимающей указатель на фактический класс, - не достаточный признак. Пусть

Код: Выделить всё

TEvent
{
 private:
  volatile bool f;
 public :
  virtaual void Processed()=0;
};
class TCharEvent: public TEvent
{
};
class TUnichar32Event: public TCharEvent
{
 public:
   public:
 virtaual void Processed()
 {
  f=true;
 }
 chart32_t Code;
};
class TUnichar16Event: public TCharEvent
{
 public:
   public:
 virtaual void Processed()
 {
  f=true;
 }
 union
 {
  wchar_t Code;
  wchar_t SurrogatCode[2];
 };
};
class TAnsicharEvent: public TCharEvent
{
 public:
   public:
 virtaual void Processed()
 {
  f=true;
 }
 char Code;
};
class TLButtonEvent: public TEvent
{
 public:
   public:
 virtaual void Processed()
 {
  f=true;
 }
 int x;
 int y;
};
и по каким то причинам решено TUncar32Event и TAnsicharEvent обрабатывать в одном обработчике, принимающем указатель на TCharEvent, TLButttonEvent - в другой, а TUnichar16Event - не обрабатывать вообще. Хорошо, когда вызываемый и вызывающий код прописаны в одном проекте, тогда просто используем указатель в качестве фактического параметра и ни каких гвоздёв. А если они в разных проектах? Если я передам один указатель на функцию, то он будет указывать только на одну версию и тест показывает, что по указателю на функцию вызывается та версия, на которую он указывает, всегда одна и та же. Тот же тест показывает, что при вызове функции по имени самой функции стандарт соблюдается и вызываемая версия зависит от фактического класса объекта, на которую указывает параметр. А как это достигается? Может отсюда можно вытянуть способ выбора версии в стороннем вызывающем коде?