2009-12-10 3 views
3

В моей программе C++:виртуальные функции в C++

#include<iostream.h> 

class A 
{ 
    public: 
    virtual void func() 
    { 
     cout<<"In A"<<endl; 
    } 
}; 

class B:public A 
{ 
    public: 
    void func() 
    { 
     cout<<"In B"<<endl; 
    } 
}; 

class C:public B 
{ 
    public: 
    void func() 
    { 
     cout<<"In C"<<endl; 
    } 
}; 

int main() 
{ 
    B *ptr=new C; 
    ptr->func(); 
} 

оператор должен вызвать B::func(). Однако вызывается функция, C::func(). Пожалуйста, пролите свет на это. После удаления виртуального ключевого слова в классе «А» этого больше не происходит.

ответ

3

Основы вы должны прочитать C++ FAQ Lite on Virtual Functions.

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

+0

Но разве факт, что я переопределял func() в классе B, отвлекает виртуальную природу функции? –

+0

Прочтите FAQ :) Если вы создаете метод виртуальный в базовом классе, нет необходимости помещать ключевое слово 'virtual' в любой производный класс - он будет виртуальным в любом случае. Если вы * перегрузили * функцию как с разными параметрами, то она будет работать практически не. –

7

Как только объявленная виртуальная функция будет виртуальной во всех производных классах (независимо от того, явно ли вы это указали или нет). Таким образом, func() является виртуальным в классах A, B и C.

1

оператор должен вызвать B :: FUNC()

Поскольку точки указатель на объект класса C, он будет вызывать функцию в классе C.

Виртуальные функции приводят к run time binding, что означает, что функция, которая будет называться, будет определяться на основе объекта, на который указывает указатель, а не типа указателя, объявленного во время компиляции.

1

В этом суть полиморфизма. Основная функция не должна знать, что ptr фактически указывает на объект класса C, ему нужно только знать, что доступный интерфейс по крайней мере тот, который определен в классе B (поэтому вы объявляете его как B *ptr, если вам нужны функции, специфичные для C, вам нужно будет сделать C *ptr).

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

Если нет виртуального ключевого слова, это говорит компилятору, что не может быть альтернативной реализации, и жестко привязывает его к B-реализации напрямую.

0

Если бы вы сделали:

B *obj = new B; 

Тогда бы назвали B :: FUNC().
Чтобы активировать функцию, которую вы ожидаете, вы должны удалить новую реализацию func в C.
Если вы используете виртуальную функцию, вы на самом деле говорите, что я не знаю, какой тип объекта у меня внутри, если он от одного и того же семейство объектов (В этом А есть «отец» «семьи»). Все, что вы знаете, состоит в том, что каждый член «семьи» должен выполнять другую работу для определенной части.Например:

class Father 
{ 
public: 
    virtual void func() { cout << "I do stuff"; } 
}; 
class Child : public Father 
{ 
public: 
    virtual void func() { cout << "I need to do something completely different"; } 
}; 

int main() 
{ 
    Father *f = new Father; 
    f->func(); // output: I do stuff 
    delete f; 
    f = new Child; 
    f->func(); // output: I need to do something completely different 
    delete f; 
} 
Смежные вопросы