Указатели на виртуальные функции-члены
От: What Беларусь  
Дата: 18.02.04 13:08
Оценка:
Не могу понять логику работы компилятора (см. комментарии).
Компилировал на VC++ 7.1
class CBase
{
public:
    virtual void f()
    {
        std::cout << "CBase::f()\n";
    }
};

class CDerived : public CBase
{
public:
    virtual void f()
    {
        std::cout << "CDerived::f()\n";
    }
};

typedef void (CBase::* TPtrBase)();
typedef void (CDerived::* TPtrDerived)();

void main()
{
    CDerived d;
    TPtrBase pBase = CBase::f;
    TPtrDerived pDerived = CDerived::f;
    // pBase = pDerived; // Не компилируется, почему?
    pDerived = pBase;    // Почему тогда это компилируется?
    d.CBase::f();        // Вызывается функция базового класса. Всё ок.
    (d.*pDerived)();     // Вызывается функция класса-наследника. Всё ок.
    (d.*pBase)();        // Вызывается функция класса-наследника. Почему?    
}
... << RSDN@Home 1.1.0 stable >>
Re: Указатели на виртуальные функции-члены
От: jazzer Россия Skype: enerjazzer
Дата: 18.02.04 13:15
Оценка: 2 (1)
Здравствуйте, What, Вы писали:

W>Не могу понять логику работы компилятора (см. комментарии).

W>Компилировал на VC++ 7.1
W>
W>class CBase
W>{
W>public:
W>    virtual void f()
W>    {
W>        std::cout << "CBase::f()\n";
W>    }
W>};

W>class CDerived : public CBase
W>{
W>public:
W>    virtual void f()
W>    {
W>        std::cout << "CDerived::f()\n";
W>    }
W>};

W>typedef void (CBase::* TPtrBase)();
W>typedef void (CDerived::* TPtrDerived)();

W>void main()
W>{
W>    CDerived d;
W>    TPtrBase pBase = CBase::f;
W>    TPtrDerived pDerived = CDerived::f;
W>    // pBase = pDerived; // Не компилируется, почему?
потому что у наследника могут быть функции, которых нет в базовом
W>    pDerived = pBase;    // Почему тогда это компилируется?
потому что у наследника есть все функции, которые есть в базовом
W>    d.CBase::f();        // Вызывается функция базового класса. Всё ок.
W>    (d.*pDerived)();     // Вызывается функция класса-наследника. Всё ок.
W>    (d.*pBase)();        // Вызывается функция класса-наследника. Почему?    
таково свойство виртуальных функций и указателей на них.
W>}
W>
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Указатели на виртуальные функции-члены
От: achp  
Дата: 18.02.04 13:21
Оценка: 6 (1)
Здравствуйте, What, Вы писали:

W>
W>void main()
W>{
W>    CDerived d;
W>    TPtrBase pBase = CBase::f;
W>    TPtrDerived pDerived = CDerived::f;

// Правильно так: &CDerived::f

W>    // pBase = pDerived; // Не компилируется, почему?

// Потому, что не всякая функция-член производного класса присутствует в базовом.
// Например, класс CDerived мог бы определить g(). Преобразование &CDerived::g к типу TPtrBase небезопасно
// и должно выполняться явно.

W>    pDerived = pBase;    // Почему тогда это компилируется?

// Всякая функция-член базового класса присутствует в производном. Все в порядке.

W>    d.CBase::f();        // Вызывается функция базового класса. Всё ок.

// Еще бы, здесь явная квалификация.

W>    (d.*pDerived)();     // Вызывается функция класса-наследника. Всё ок.
W>    (d.*pBase)();        // Вызывается функция класса-наследника. Почему?    

// Потому что указатели на функции-члены вполне поддерживают полиморфизм.
// Тип указателя на член void (CBase::*TPtrBase)() говорит о том, что он может быть применен к любому объекту CBase
// или производному от CBase. Однако, если указуемая функция-член виртуальна, для разрешения вызова используется
// динамический тип объекта, а не CBase!

W>}
W>
Re: Указатели на виртуальные функции-члены
От: Vamp Россия  
Дата: 18.02.04 13:24
Оценка: 2 (1)
А что тебя удивляет?

W> // pBase = pDerived; // Не компилируется, почему?
W> pDerived = pBase; // Почему тогда это компилируется?


Потому же, почему

CBase* pb=new CBase;
CDerived* pd=new CDerived;
pb=pd; //(1)
pd=pb; //(2)

(1) компилируется, а (2) — нет.

W> (d.*pBase)(); // Вызывается функция класса-наследника. Почему?

Так для того она и виртуальная! pBase указывает не на саму функцию, а на запись в vtable. Для класса дерайвед эта запись указывает на функцию производного класса.
Да здравствует мыло душистое и веревка пушистая.
Re: Указатели на виртуальные функции-члены
От: What Беларусь  
Дата: 18.02.04 13:32
Оценка:
Здравствуйте, What, Вы писали:

W>Не могу понять логику работы компилятора (см. комментарии).

W>Компилировал на VC++ 7.1

Теперь понял. Спасибо всем за ответы!
... << RSDN@Home 1.1.0 stable >>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.