У кого вызывается функция при вызове f1 () через Derived :: f2 ()?

#include <iostream>
#include <string>
using namespace std;

class Base {
public:
Base(const string& s): str(s) {cout<<"Base::ctor\n";}
Base(const Base& b): str(b.str) {cout<<"Base::copy ctor\n";}
virtual ~Base() {cout<<"Base::dtor\n";}
void f1() {cout<<"Base::f1()\n"; f2();} //2 orders
virtual void f2() {cout<<"Base::f2()\n";}

private:
string str;
};

class Derived : public Base {
public:
Derived(const string& s): Base(s)
{cout<<"Derived::ctor\n";}
Derived(const Derived& d): Base(d)
{cout<<"Derived::copy ctor\n";}
~Derived() {cout<<"Derived::dtor\n";}
virtual void f1() {cout<<"Derived::f1()\n"; f2();}
void f2() {cout<<"Derived::f2()\n"; f1();} //jumps from here to Leaf's f1()
};

class Leaf : public Derived {
public:
Leaf(const string& s): Derived(s)
{cout<<"Leaf::ctor\n";}
Leaf(const Leaf& dd): Derived(dd)
{cout<<"Leaf::copy ctor\n";}
~Leaf() {cout<<"Leaf::dtor\n";}
void f1() {cout<<"Leaf::f1()\n"; f3();}
void f3() {cout<<"Leaf::f3()\n";}
};int main() {
Leaf * p = new Leaf("Hello");
Base * p2 = new Leaf(*p);

p2->f1();

delete p2;
delete p;
return 0;
}

Привет,

Этот вопрос является экзаменационным, но мне очень трудно найти правильный способ описать его и найти его в Интернете.

в соответствии :

p2->f1();

выход:

 Base::f1()
Derived::f2()
Leaf::f1()
Leaf::f3()

в производном f2 () есть вызов для f1 (). кого будут звать? f1 () типа Base или f1 () из Leaf?
Из того, чему меня учили, компилятор всегда ищет функцию в типе слева. (Base * p2 = new Leaf (* p)) Но здесь я вижу, что это относится к f1 () класса Leaf.
Я вижу, что это Лиф, но не понимаю, почему …

спасибо за помощников!

1

Решение

Чтобы быстро ответить на ваш вопрос: Derived :: f1 () вызывается в Derived :: f2 ().

Чтобы понять, почему вызывается Derived :: f1 (), вам, вероятно, понадобятся знания «C ++ name скрывается в наследовании», к которым вы можете обратиться в некоторых онлайн-статьях, таких как:

Вам также необходимо знание «поиска по неквалифицированному имени», которое вы можете найти в разделе «Определение функции-члена» на этой веб-странице: Неквалифицированный поиск имени.

Таким образом, основные моменты:

  • В случае вашего кода Derived :: f1 () скрывает Base :: f1 (), что означает, что Base :: f1 () не виден членам Derived.
  • Вызов f1 () — это случай поиска имени без оговорок.
  • Имена, как правило, смотрят изнутри наружу. Когда f1 () вызывается в Derived :: f2 (), компилятор сначала ищет в самой внутренней области видимости, которой является само тело Derived :: f2 (); тогда весь класс Производная сфера. Поскольку f1 () может быть найден в области действия Derived, он становится тем, который вызывается.
  • Вы можете подумать, что Base :: f1 () выглядит как находящийся на одном уровне с Derived :: f1 () из-за наследования, а затем удивляетесь, почему Base :: f1 () не вызывается. Напомним, имя скрывается.

Процесс звонка должен быть следующим:

  1. В основном(), p2->f1(); выполнен.
  2. Поскольку p2 является указателем на Base, имя «f1» ищется в списке методов Base.
  3. Обратите внимание, что Base :: f1 () НЕ виртуальный, поэтому Base :: f1 () вызывается («Base :: f1 ()»). Да, f1 () объявлен как виртуальный в Derived, но это не влияет на виртуальную таблицу Base.
  4. Base :: f1 () вызывает f2, который является виртуальным методом Base. Поскольку f2 переопределяется только в Derived, Derived :: f2 () — это то, что на самом деле называется («Derived :: f2 ()»).
  5. Derived :: f2 () вызывает функцию f1 (), которая фактически является Derived :: f1 (). Поскольку Derived :: f1 () объявлен как виртуальный и переопределен в Leaf, именно Leaf :: f1 () в конечном итоге вызывается («Leaf :: f1 ()»).
  6. Leaf :: f1 () вызывает функцию f3 (), то есть Leaf :: f3 (). f3 () — это метод, который есть только у Leaf, поэтому он просто вызывается («Leaf :: f3 ()»).
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]