Не могу понять логику работы компилятора (см. комментарии).
Компилировал на 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 >>
Здравствуйте, 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>
Здравствуйте, 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>
А что тебя удивляет?
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. Для класса дерайвед эта запись указывает на функцию производного класса.
Здравствуйте, What, Вы писали:
W>Не могу понять логику работы компилятора (см. комментарии).
W>Компилировал на VC++ 7.1
Теперь понял. Спасибо всем за ответы!
... << RSDN@Home 1.1.0 stable >>