Re[7]: virtual static и static virtual
От: MaximE Великобритания  
Дата: 19.07.03 14:38
Оценка: 10 (1)
Здравствуйте, LCR, Вы писали:

LCR>Здравствуйте, MaximE, Вы писали:


ME>>Как раз для этой цели используют идиому double dispatch.


LCR>MaximE, можно по-подробнее. Что это за идиома?


Паттерн visitor использует идиому double dispatch:

#include <iostream>
#include <memory>

struct visitor
{
    virtual void visit(struct A&) = 0;
    virtual void visit(struct B&) = 0;
    virtual void visit(struct C&) = 0;
};

struct A
{
    virtual void accept(visitor& v) { v.visit(*this); } // double dispatch
};

struct B : A
{
    virtual void accept(visitor& v) { v.visit(*this); } // double dispatch
};

struct C : B
{
    virtual void accept(visitor& v) { v.visit(*this); } // double dispatch
};

struct concrete_visitor : visitor
{
    virtual void visit(A&) { std::cout << "visiting A\n"; }
    virtual void visit(B&) { std::cout << "visiting B\n"; }
    virtual void visit(C&) { std::cout << "visiting C\n"; }
};

int main()
{
    std::auto_ptr<A> a1(new A);
    std::auto_ptr<A> a2(new B);
    std::auto_ptr<A> a3(new C);

    concrete_visitor v;

    a1->accept(v);
    a2->accept(v);
    a3->accept(v);

    return 0;
}
Re[11]: Перпендикулярные свойства
От: folk Россия  
Дата: 19.07.03 14:41
Оценка: 1 (1)
Здравствуйте, Vi2, Вы писали:

Vi2>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.


Полностью согласен.

Vi2>Смысл? Не знаю.


С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса:
1. динамически — у экземпляра
2. статически — у класса (например где-нибудь в шаблонных глубинах экземпляр недоступен, но известен класс, специализирующий этот шаблон)

Вот как это выглядит в C++:

struct Abstract
{
  virtual const char* typeName() const = 0;
};

struct Foo : public Abstract
{
  static const char* typeNameStatic()
    {return "Foo";}
  virtual const char* typeName() const 
    {return typeNameStatic();}  
};

struct Bar : public Abstract
{
  static const char* typeNameStatic()
    {return "Bar";}
  virtual const char* typeName() const 
    {return typeNameStatic();}  
};

Динамический вызов: pObj->typeName(). При этом методу передается this, который ему совершенно не нужен.
Статический вызов в глубинах шаблона: typename T::typeNameStatic()

А вот как могло бы выглядеть со static virtual:

struct Abstract
{
  static virtual const char* typeName() = 0;
};

struct Foo : public Abstract
{
  static virtual const char* typeName()
    {return "Foo";}
};

struct Bar : public Abstract
{
  static virtual const char* typeName()
    {return "Bar";}  
};

Указатель на typeName() присутствует в таблице виртуальных функций, поэтому можем вызывать так: pObj->typeName()
И в то же время поскольку этой функции не передается неявный параметр this, то где-нибудь в шаблоне можем написать так: typename T::typeName()

ИМХО удобство налицо
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[12]: Перпендикулярные свойства
От: folk Россия  
Дата: 19.07.03 15:00
Оценка:
Здравствуйте, folk, Вы писали:

Перечитал и понял что могут не так понять.
typename T::typeNameStatic() — так в коде писать не надо, это я так подчеркивал что T не абы что, а тип специализирующий шаблон.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[13]: Перпендикулярные свойства
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 20.07.03 09:00
Оценка:
Здравствуйте, Vi2, Вы писали:

[]

Vi2>Так они и так так вызываются. Просто не реализовано и запрещено.


Все-таки я не пойму в чем смысл виртуальности статической функции? Объясни?

У них разная семантика. Это примерно, как: "А почему бы на свой рабочий стол не положить колесо от Камаза?".
Ты говоришь, что можно. Я спрашиваю — зачем?
Re[12]: Перпендикулярные свойства
От: _wqwa США  
Дата: 20.07.03 11:09
Оценка:
Здравствуйте, folk, Вы писали:

F>Здравствуйте, Vi2, Вы писали:


Vi2>>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.


F>Полностью согласен.


Vi2>>Смысл? Не знаю.


F>С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса:

примерчик скипнут

Будешь смеяться, но твой пример -- единственная ситуация, когда мне нужны были статичекме виртульные ф-ции. Я не видел ни одной другой задачи, для которой они бы были нужны. Если у тебя были другие задачи, где применение функций статик-виртуал было бы целесообразно -- плз, приведи пример.
Кто здесь?!
Re[13]: Перпендикулярные свойства
От: Дмитро  
Дата: 20.07.03 12:14
Оценка:
Здравствуйте, _wqwa, Вы писали:


_>Будешь смеяться, но твой пример -- единственная ситуация, когда мне нужны были статичекме виртульные ф-ции. Я не видел ни одной другой задачи, для которой они бы были нужны. Если у тебя были другие задачи, где применение функций статик-виртуал было бы целесообразно -- плз, приведи пример.


Пожалуйста!
struct Abstract
{
  static virtual Abstract* create() = 0;
};

struct Foo : public Abstract
{
  static virtual Abstract* create() {return new Foo();}
};

struct Bar : public Abstract
{
  static virtual Abstract* create() {return new Bar();}
};

Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).

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

Нарушает ли "статическая виртуальность" концептуальную целостность языка? Полагаю, что нет. Я по крайней мере сложностей в реализации не вижу. И не вижу каких-либо подводных камней связанных с использованием этой фичи.
--
Дмитрий
Re[14]: Перпендикулярные свойства
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 20.07.03 13:07
Оценка:
Здравствуйте, Дмитро, Вы писали:

[]

Д>Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).


А вот ты убери virtual! Получиться тоже самое.

Д>Можно ли без этого обойтись? Конечно можно! Для этого придумали такой паттерн как абстрактная фабрика. (В принципе, можно даже программировать в терминах машин Тьюринга, где нет ни классов, ни методов, а только лента, входные данные и текущее состояние.)


Ну это ты загнул! Ты похоже сам не понял, чего написал. Приведи пример использования.

хъ
Re[14]: Перпендикулярные свойства
От: WolfHound  
Дата: 20.07.03 14:26
Оценка:
Здравствуйте, Дмитро, Вы писали:

Д>Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).

На фига подобного. Но если тебе они нужны, то я их уже изобрел Виртуальные конструкторы 2
Автор: WolfHound
Дата: 09.06.03
... << RSDN@Home 1.1 alpha 1 >>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: Перпендикулярные свойства
От: folk Россия  
Дата: 20.07.03 22:02
Оценка:
Здравствуйте, _wqwa, Вы писали:

_>Здравствуйте, folk, Вы писали:


F>>Здравствуйте, Vi2, Вы писали:


Vi2>>>Выбор адреса функции и вызов функции с дополнительным параметром — это изначально разные вещи. Можно выбрать функцию из vtable, но не передавать туда this.


F>>Полностью согласен.


Vi2>>>Смысл? Не знаю.


F>>С твоего позволения приведу первый пришедший в голову примерчик, который демонстрирует удобство static virtual. Допустим мы хотим иметь возможность запрашивать текстовую строку — имя класса:

_>примерчик скипнут

_>Будешь смеяться, но твой пример -- единственная ситуация, когда мне нужны были статичекме виртульные ф-ции. Я не видел ни одной другой задачи, для которой они бы были нужны. Если у тебя были другие задачи, где применение функций статик-виртуал было бы целесообразно -- плз, приведи пример.


Ага, значит и для тебя этот пример жизненный! Можно придумать много вариаций на его тему: вернуть указатель на коласс COM, вернуть счетчик кол-ва экземпляров класса, ... — имхо вполне распространенные ситуации.

У меня не было задач где пришлось бы использовать виртуальное наследование (тьфу-тьфу-тьфу), но ведь и оно кому-то нужно.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[15]: Перпендикулярные свойства
От: Дмитро  
Дата: 21.07.03 01:33
Оценка:
Здравствуйте, Alexey Shirshov, Вы писали:

AS>Здравствуйте, Дмитро, Вы писали:


AS>[]


Д>>Надо отметить, что так называемые виртуальные конструкторы в Borland C++ есть по смыслу ни что иное как такие вот статические виртуальные функции (синтаксис, конечно другой).


AS>А вот ты убери virtual! Получиться тоже самое.


То же самое не получится.
#include <stdio.h>

struct A {
    /*virtual*/ static void fs() {
        printf("A::fs()\n");
    }
    virtual void fn() {
        fs();
    }
};

struct B: A {
    /*virtual*/ static void fs() {
        printf("B::fs()\n");
    }
};

int main() {
    B b;
    b.fn(); // <-- отсюда вызовется A::fs()
    B::fs();
    return 0;
}


В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().

Предвижу следующий совет: "Убери static и поставь virtual". К сожалению, это тоже не подходит, поскольку хотелось бы метод fs() вызывать без экземпляра, например, так: B::fs().

Д>>Можно ли без этого обойтись? Конечно можно! Для этого придумали такой паттерн как абстрактная фабрика. (В принципе, можно даже программировать в терминах машин Тьюринга, где нет ни классов, ни методов, а только лента, входные данные и текущее состояние.)


AS>Ну это ты загнул! Ты похоже сам не понял, чего написал. Приведи пример использования.


Понял. Я просто переутрировал!

То, что я хотел сказать, так это то, что все языки программрования являются выразительно равномощными. Это означает, что любой вычислительный алгоритм можно представить на любом языке. И то, что язык поддерживает ООП, шаблоны и/или "частичную специализацию" отнюдь не позволяет решать какой-то новый класс задач, недоступных для решения ранее. "Вкусности" позволяют лишь решать те же самые задачи быстрее, качественнее, надежнее. И на мой взляд "статическая виртуальность" одна из таких вкусностей.
--
Дмитрий
Re[8]: virtual static и static virtual
От: LCR Россия lj://_lcr_
Дата: 21.07.03 04:38
Оценка:
Здравствуйте, MaximE, Вы писали:

LCR>>MaximE, можно по-подробнее. Что это за идиома?


ME>Паттерн visitor использует идиому double dispatch:


ME>
ME><...>
ME>


Спасибо. (Awaken забыл ещё указать ссылку на банду четырёх

Удалено избыточное цитирование. -- ПК.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[16]: Перпендикулярные свойства
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 21.07.03 05:02
Оценка:
Здравствуйте, Дмитро, Вы писали:

[]

Д>В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().


Это не тот пример, который я бы хотел видеть, но все-равно. Ты говоришь о связывании. Чего с чем? Статическая функция не может быть связана. В этом весь прикол. Ее вызов определяется типом на этапе компиляции. Всегда! Тогда как определение версии вызова виртуальной функции откладывается и определяется в рантайме используя не тип, а экземпляр типа! Статическая функция не привязана к экземпляру, поэтому она никогда по определению не сможет стать виртуальной.

Д>Предвижу следующий совет: "Убери static и поставь virtual". К сожалению, это тоже не подходит, поскольку хотелось бы метод fs() вызывать без экземпляра, например, так: B::fs().


И каким образом fn вызовет B::fs() даже если ты гипотетически смог статическую функцию сдеслать виртуальной?

хъ

Д>Понял. Я просто переутрировал!


Д>То, что я хотел сказать, так это то, что все языки программрования являются выразительно равномощными. Это означает, что любой вычислительный алгоритм можно представить на любом языке. И то, что язык поддерживает ООП, шаблоны и/или "частичную специализацию" отнюдь не позволяет решать какой-то новый класс задач, недоступных для решения ранее. "Вкусности" позволяют лишь решать те же самые задачи быстрее, качественнее, надежнее. И на мой взляд "статическая виртуальность" одна из таких вкусностей.


Как это будет реализовываться. Ты говоришь, было бы неплохо вечерком, слетать на Марс или, на худой конец, Луну, а вместо этого приходится переться в кино. Ну я согласен, но приведи пример, как это может быть технически сделано.
Re[17]: Перпендикулярные свойства
От: Дмитро  
Дата: 21.07.03 05:49
Оценка: 12 (1)
Здравствуйте, Alexey Shirshov, Вы писали:

Д>>В выделенной строке вызовется статический метод A::fs(). Это потому, что в методе A::fn() используется ранее связывание для вызова статического метода. Если бы использовалось позднее связываение, то вызвался бы статический метод B::fs().


AS>Это не тот пример, который я бы хотел видеть, но все-равно. Ты говоришь о связывании. Чего с чем? Статическая функция не может быть связана. В этом весь прикол. Ее вызов определяется типом на этапе компиляции. Всегда! Тогда как определение версии вызова виртуальной функции откладывается и определяется в рантайме используя не тип, а экземпляр типа! Статическая функция не привязана к экземпляру, поэтому она никогда по определению не сможет стать виртуальной.


AS>И каким образом fn вызовет B::fs() даже если ты гипотетически смог статическую функцию сдеслать виртуальной?


AS>Как это будет реализовываться. Ты говоришь, было бы неплохо вечерком, слетать на Марс или, на худой конец, Луну, а вместо этого приходится переться в кино. Ну я согласен, но приведи пример, как это может быть технически сделано.


Я приведу С++'ный псевдокод и его возможную трансляцию в С.
struct A {
     int m_a;

     virtual void f_virtual_nonstatic(int) { /* 1 */ }
     void f_nonvirtual_nonstatic(int) { /* 2 */ }
     virtual static f_virtual_static(int) { /* 3 */ }
     static f_nonvirtual_static(int) { /* 4 */ }
     A() { /* 5 */ }
     void test() {
          f_virtual_nonstatic(10);
          f_nonvirtual_nonstatic(20);
          f_virtual_static(30);
          f_nonvirtual_static(40);
     }
};

struct B: A {
     int m_b;

     virtual void f_virtual_nonstatic(int) { /* 6 */ }
     void f_nonvirtual_nonstatic(int) { /* 7 */ }
     virtual static f_virtual_static(int) { /* 8 */ }
     static f_nonvirtual_static(int) { /* 9 */ }
     B() { /* 10 */ }
};


struct A;
struct A__vtbl { // объявление таблицы виртуальных методов класса A
     void (*f_virtual_nonstatic)(A *, int);
     void (*f_virtual_static)(int);
};

struct A { // объявление самого класса A
     A__vtbl const *pvtbl; // указатель на таблицу виртуальных методов
     int m_a;
};

// реализации методов класса A
void A__f_virtual_nonstatic(A *, int) { /* 1 */ }
void A__f_nonvirtual_nonstatic(A *, int) { /* 2 */ }
void A__f_virtual_static(int) { /* 3 */ }
void A__f_nonvirtual_static(int) { /* 4 */ }

A__vtbl g_A__vtbl = { // таблица виртуальных методов класса A (сегмент инициализированных данных)
     A__f_virtual_nonstatic,
     A__f_virtual_static
};
void A__ctor(A *this) { // конструктор класса A
     this->pvtbl = &g_A__vtbl;
     /* 5 */
}

// -----------------------------------------

struct B;
struct B__vtbl { // объявление таблицы виртуальных методов класса B
     void (*f_virtual_nonstatic)(B *, int);
     void (*f_virtual_static)(int);
};

struct B { // объявление самого класса B
     B__vtbl const *pvtbl; // указатель на таблицу виртуальных методов
     int m_a; // член-данное, унаследованное от A
     int m_b; // собственное член-данное.
};

// реализации методов класса A
void B__f_virtual_nonstatic(B *, int) { /* 6 */ }
void B__f_nonvirtual_nonstatic(B *, int) { /* 7 */ }
void B__f_virtual_static(int) { /* 8 */ }
void B__f_nonvirtual_static(int) { /* 9 */ }

B__vtbl g_B__vtbl = { // таблица виртуальных методов класса B (сегмент инициализированных данных)
     B__f_virtual_nonstatic,
     B__f_virtual_static
};
void B__ctor(B *this) { // конструктор класса B
     A__ctor(this); // вызов конструктора базового класса
     this->pvtbl = &g_B__vtbl; // настройка своей таблицы виртуальных методов
     /* 10 */
}

// -----------------------------------------

void A__test(A *this) {
//f_virtual_nonstatic(10);
(this->pvtbl->f_virtual_nonstatic)(this, 10);

//f_nonvirtual_nonstatic(20);
A__f_nonvirtual_nonstatic(this, 20);

//f_virtual_static(30); виртуальный вызов статической функции!!!
(this->pvtbl->f_virtual_static)(30);

//f_nonvirtual_static(40);
A__f_nonvirtual_static(40);
}
--
Дмитрий
Re[18]: Перпендикулярные свойства
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 21.07.03 06:05
Оценка:
Здравствуйте, Дмитро, Вы писали:

[]

Статическая функция по определению может быть вызвана без наличия живого экземпляра типа. Кроме этого в нее не передается указатель на этот экземпляр (т.е. метод вызова не thiscall). У тебя эти два требования не выполняються.
Т.е. статическая виртуальная функция ведет себя точно также как виртуальная. Поэтому я тебе и советовал убрать static, что приведет к тем же результатам.
Re: virtual static и static virtual
От: deviv  
Дата: 21.07.03 07:23
Оценка: 20 (3)
В чем принципиальная сложность совместить virtual и static?
Проблема (принципиальная, еще раз подчеркну) в том, что по дизайну языка C++ static методы никогда не должны зависить от конкретного объекта, а virtual должны вызваться через виртуальную таблицу, доступ к которой осуществляется через объект.

Про это уже не раз говорили в этом топике. Приводились примеры как такой механизм реализвать, и доводы почему так делать не надо.

Пример, когда компилятор определяет "виртуальность" вызова статической функции из контекста:
1) если вызываем через объект или напрямую из нестатического вызова, то вызов через виртуальную таблицу
2) если вызов через имя класса или напрямую из статического метода, то вызов как стандартной функции.

Подобное поведение не вписывается в идиомы virtual и static (см. выше). Проблемы:
1) зависимость от контекста: перенос кода из статического метода в нестатический (или наоборот) может привести к тому, что код станет работать по-другому
2) нет транзитивности: как быть с такой цепочкой вызовов: обычный метод -> виртуальный статический->виртуальный статический? Оба статических вызова эквиваленты, но первый пойдет через виртуальную таблицу, второй напрямую.

Я уверен, что здесь куча других подводных комней. Какой бы не был базовай дизайн, действовать вопреки нему — это рыть себе могилу. Нужно придумать либо что-то другое, либо разрабавытать новыцй язык на базе C++.

А если что-то другое? Частично проблему может решить введение метакласса: виртуальные статические методы можно вызывать через его "виртаальную таблицу". Но это лишь решает проблему №1 и оставляет без решения проблему №2. И все же... создание "виртуальных конструкторов" по такой схеме — очень удобное решение. Именно так они реализованы в Делфи.
WBR,
Влад Волосюк
Re[19]: Перпендикулярные свойства
От: Дмитро  
Дата: 21.07.03 07:53
Оценка:
Здравствуйте, Alexey Shirshov, Вы писали:

AS>Статическая функция по определению может быть вызвана без наличия живого экземпляра типа. Кроме этого в нее не передается указатель на этот экземпляр (т.е. метод вызова не thiscall).


Согласен! Согласен и с тем, что предыдущий пример этого не демонстрирует. Исправляю свою неточность сейчас.
. . .
int main() {
     A::f_virtual_static();
     B::f_virtual_static();
     return 0;
}

. . .
int main() {
//A::f_virtual_static(10); -- здесь нет живого экземпляра и указатель на него не передается.
     A__f_virtual_static(10);

//B::f_virtual_static(11); -- здесь то же самое
     B__f_virtual_static(11);

     return 0;
}
--
Дмитрий
Re[20]: Перпендикулярные свойства
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 21.07.03 08:48
Оценка:
Здравствуйте, Дмитро, Вы писали:

[]

И где полиморфизм?
Re[11]: Перпендикулярные свойства
От: LaptevVV Россия  
Дата: 21.07.03 09:09
Оценка:
Здравствуйте, Артур, Вы писали:

LVV>>Прощу прощения, но виртуальность-нестатичность или статичность-невиртуальность — это принципиальный вопрос семантики языка, а не доступа-реализации к функции.

LVV>>Статическая функция — это функция класса. Она принципиально в одном экземпляре.
LVV>>А виртуальная функция — это функция объекта. Функция класса СУЩЕСТВУЕТ ДО объявления объекта. А виртуальная функция (ну, хорошо, vtable) — только после объявления объекта. Как виртуальная функция может быть статической, если их столько, сколько объектов???????
А>Почему это vtable существует только после объявления объекта? Указатель на vtable заполняется при создании объекта, а сам виртуальная таблица генерируется для класса, и существует независимо от того, создавал ли ты объекты данного класса или нет.

Ну, хорошо, не сама vtable, а указатель на vtable. Суть от этого не меняется. Указателей столько, сколько объектов. А статическая функция — одна.

A>Я согласен с VI2, что статичность и виртуальность скорее перпендикулярные понятия,

а зависимыми они стали только благодаря реализации (vtable как член класса).
А я согласен с Павлом Кузнецовым:
ПК>static означает, что функцию-член можно вызывать, не имея объекта соответствующего
класса. Виртуальный вызов подобным образом сделать принципиально невозможно.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: virtual static и static virtual
От: Дмитро  
Дата: 21.07.03 10:30
Оценка:
Здравствуйте, deviv, Вы писали:

D>2) нет транзитивности: как быть с такой цепочкой вызовов: обычный метод -> виртуальный статический->виртуальный статический? Оба статических вызова эквиваленты, но первый пойдет через виртуальную таблицу, второй напрямую.


Черт подери!!! Это пока что самый убедительный довод против "статической виртуальности"!
--
Дмитрий
Re[20]: Перпендикулярные свойства
От: _wqwa США  
Дата: 21.07.03 12:36
Оценка:
Здравствуйте, Дмитро, Вы писали:

Слушай, ты гладко и стройно рассуждаешь, но я все равно одного не понимаю.
Как определяется класс (динамический тип), для которого вызывается функция static virtual.

Если брать эти квалификаторы по отдельности -- тут вопросов нет:
Со static -- все понятно -- какой класс в префиксе вызова указали (или какой статический тип имеет экземпляр класса или указатель, через который вызвали), для такого и вызывается.
С virtual -- тоже понятно. Берем указатель на экземпляр, смотрим его действительный класс (динамик-тайп) и для этого класса и вызываем функцию.

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