2009-12-12 4 views
2

Меня попросил мой друг проблема с виртуальной функцией.один вопрос о виртуальной функции C++

Если дочерний объект вызывает виртуальную функцию, при каких условиях эта виртуальная функция выполняется фактически в реализации отца?

+3

В C++, термин «базовый класс» используются, когда вам скажем, «отец» и «производный класс», когда вы говорите «ребенок». – 2009-12-12 20:11:37

+0

Что означает «эта виртуальная функция на самом деле исполняется в реализации отца»? Реализация ребенка выполняет родительскую реализацию? Или родительская реализация выполняется напрямую, а реализация ребенка вообще не выполняется? – AnT

ответ

0

Если деструктор дочернего класса уже вызван, тогда объект теперь имеет тип родителя, поэтому будут вызываться виртуальные функции родителя.

+1

В стандарте C++, конечно, нет такой вещи. – 2009-12-12 20:12:44

+0

Hi Ned, Не могли бы вы привести некоторые примеры? Hi Neil Каков ваш ответ на этот вопрос? – skydoor

+0

Я не могу привести этот стандарт, но я его не понял: http://c2.com/cgi/wiki?PureVirtualFunctionCalled и http://msdn.microsoft.com/en-us/magazine/cc163897. aspx –

3

Я думаю, вам нужно опубликовать некоторый код, чтобы уточнить, о чем вы просите, но (за исключением деструктора) функция базового класса не будет вызываться, если ребенок не вызывает itt явно из своей собственной функции. Например, в:

struct A { 
    virtual ~A() {} 
    virtual void f() {} 
}; 

struct B : public A { 
    virtual void f() {} 
}; 

int main() { 
    A * a = new B; 
    a->f(); 
    delete a; 
} 

Вызывается только виртуальная функция B f(). Если вы хотите A :: f() будет называться вы должны сделать это явно:

struct B : public A { 
    virtual f() { 
     A::f(); // explicit call 
    } 
}; 

О, и, конечно, в том случае, когда B не объявить функцию - в этом случае A :: F() всегда будет вызываться.

+0

У меня пока нет кода.Я думаю, что вопрос, как этот класс B { виртуальный е() {соиЬ << << епсИ "в Базе!";}} класс D { виртуальный е() {соиЬ <<» in Derived "<< endl;} } Существует два объекта d и b, когда d вызывает функцию df(), она показывает« в базе! ». В какой ситуации это произойдет? – skydoor

+1

Виртуальные вызовы происходят только через указатели и ссылки, а не через экземпляры объектов. – 2009-12-12 20:32:05

+0

хорошо, спасибо за ваши комментарии. Однако я думаю, что есть некоторые недоразумения. Я думаю, что вопрос в том, почему производный объект называется виртуальной функцией, но функция в базовом классе выполняется. Речь идет не о том, как вызвать функцию в базовом классе. – skydoor

0

Если этот вызов является конструктором, отправка будет статичной. Прочитайте это для получения дополнительной информации: http://cplusplus.co.il/2009/09/30/virtual-dispatching-within-a-constructor-or-a-destructor/

Вот пример из статьи я связан с:

struct A { 
    A() { f(); } 
    virtual void f() { } 
}; 

struct B : A { 
     B() :member(0) {} 
     void f() { std::cout << member; } 
    private: 
     int member; 
}; 

int main() { 
    B b; 
    return 0; 
} 

Вызванный Р A :: F, несмотря на то, что он является виртуальным и вызывается объект типа B, который имеет свою собственную реализацию.

+0

И это, и ответ Неда связаны со статической отправкой. Я думаю, что OP is about sking about virtual dispatch - его комментарий к моему ответу, похоже, указывает на это. – 2009-12-12 20:42:41

+1

Неверно сказать, что диспетчер * статический *. Отправка не статична. С точки зрения языка для виртуальных функций отправка всегда * динамическая *, но когда вызов производится из конструктора, динамический тип объекта является классом, конструктор которого в настоящее время работает. Я не знаю, откуда эта странная идея * статической отправки. Компилятор может оптимизировать его, чтобы быть статичным, но это просто специфическая оптимизация для компилятора. – AnT

+0

Итак, если я говорю (используя мой примерный код) A a; a.f(); вы говорите, что это динамическая отправка? – 2009-12-12 21:17:54

2

Невозможно понять, что именно подразумевается под вопросом в текущей форме ts.

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

class parent { 
public: 
    virtual void foo() { /* whatever */ } 
}; 

class child : parent { 
public: 
    void bar() { 
    foo(); /* call the parent's implementation, as requested */ 
    } 
}; 

Итак, вот ваш ответ.

Конечно, это интуитивно очевидно для всех, что, скорее всего, это не то, что подразумевалось под вопросом. Вполне вероятно, что подразумевалось, что дочерний класс переопределяет функцию родителя. В этом случае есть еще один очевидный ответ: версия родителя будет вызываться, если ребенок использует полное имя функции

class parent { 
public: 
    virtual void foo() { /* whatever */ } 
}; 

class child : parent { 
public: 
    virtual void foo() { /* whatever */ } 
    void bar() { 
    parent::foo(); /* call the parent's implementation, as requested */ 
    } 
}; 

Другой возможный ответ, что объект, для которого вызывается функция на самом деле имеет parent тип (поскольку нигде в этом вопросе он говорит, что ребенок должен назвать его this объекта)

class parent { 
public: 
    virtual void foo() { /* whatever */ } 
}; 

class child : parent { 
public: 
    virtual void foo() { /* whatever */ } 
    void bar() { 
    parent p; 
    p.foo(); /* call the parent's implementation, as requested */ 
    } 
}; 

Опять же, интуитивно чувствует, что это не то, что речь идет о. Скорее всего, этот вопрос должен был быть о виртуальных вызовов, сделанных из конструкторов и деструкторов

class parent { 
public: 
    parent() { 
    foo(); /* always calls `parent::foo` */ 
    } 
    virtual void foo() { /* whatever */ } 
}; 

class child : parent { 
public: 
    child() : parent() /* `parent::parent` will call `parent::foo` */ 
    {} 
    virtual void foo() { /* whatever */ } 
}; 

Однако для этого вопрос неправильно сформулирован. В последнем примере в момент вызова дочерний объект еще не существует.Память для нее уже выделена, но ее срок службы еще не начался. Неверно сказать, что вызов виртуальной функции выполняется дочерним объектом. Он выполняется родительским объектом.

Итак, чтобы возобновить вышеуказанное: вопрос настолько неоднозначно и смутно сформулирован, что в его нынешнем виде он не имеет никакого смысла.

1
  • Когда сфера базового класса явным образом используется (Base::f();)
  • Внутри конструктора базового класса (потому что конструктор производного объекта не был введен еще)
  • Внутри деструктор базового класса (поскольку получены объект уже разрушен)
0

Ответ уже предусмотрено, это может произойти во время строительства:

это также может быть забавный источник ошибок во время выполнения, поэтому обратите особое внимание конструкторы & чисто виртуальные методы вызовов в базовом классе;)

http://support.microsoft.com/kb/125749

class A; 

    void fcn(A*); 

    class A 
    { 
    public: 
     virtual void f() = 0; 
     A() { fcn(this); } 
    }; 

    class B : A 
    { 
     void f() { } 
    }; 

    void fcn(A* p) 
    { 
     p->f(); 
    } 

    // The declaration below invokes class B's constructor, which 
    // first calls class A's constructor, which calls fcn. Then 
    // fcn calls A::f, which is a pure virtual function, and 
    // this causes the run-time error. B has not been constructed 
    // at this point, so the B::f cannot be called. You would not 
    // want it to be called because it could depend on something 
    // in B that has not been initialized yet. 

    B b; 

    void main() 
    { 
    } 
Смежные вопросы