2012-06-17 7 views
37

Давайте предположим, этот сценарий, в Visual C++ 2010:Переопределение невиртуальных метод

#include <iostream> 
#include <conio.h> 

using namespace std; 

class Base 
{ 
public: 
    int b; 
    void Display() 
    { 
     cout<<"Base: Non-virtual display."<<endl; 
    }; 
    virtual void vDisplay() 
    { 
     cout<<"Base: Virtual display."<<endl; 
    }; 
}; 

class Derived : public Base 
{ 
public: 
    int d; 
    void Display() 
    { 
     cout<<"Derived: Non-virtual display."<<endl; 
    }; 
    virtual void vDisplay() 
    { 
     cout<<"Derived: Virtual display."<<endl; 
    }; 
}; 

int main() 
{ 
    Base ba; 
    Derived de; 

    ba.Display(); 
    ba.vDisplay(); 
    de.Display(); 
    de.vDisplay(); 

    _getch(); 
    return 0; 
}; 

Теоретически выход этого маленького приложения должен быть:

  • Base: Non-виртуальный дисплей.
  • База: виртуальный дисплей.
  • База: Не виртуальный дисплей.
  • Производные: Виртуальный дисплей.

потому что метод отображения класса Base не является виртуальным методом, поэтому класс Derived не должен его переопределять. Правильно?

Проблема заключается в том, что при запуске приложения, он выводит это:

  • Base: Non-виртуальный дисплей.
  • База: виртуальный дисплей.
  • Производный: Не виртуальный дисплей.
  • Производные: Виртуальный дисплей.

Так что либо я не понял понятия виртуальных методов, либо что-то странное происходит в Visual C++.

Не мог бы кто-нибудь помочь мне с объяснением?

+0

у вас будет абсолютно __Base: не виртуальный дисплей .__ при изменении вашей строки на 'de.Base :: Display()'. –

ответ

50

Да, вы недопонимаете немного.

Метод с тем же именем в производном классе скроет родительский метод в этом случае. Вы могли бы предположить, что если это не так, попытка создания метода с тем же именем, что и не виртуальный метод базового класса, должна вызывать ошибку. Это разрешено, и это не проблема - и если вы вызовете метод напрямую, как вы это сделали, он будет называться штрафом.

Но, будучи не виртуальными, механизмы поиска методов на С ++, которые допускают полиморфизм, не будут использоваться. Например, если вы создали экземпляр вашего производного класса, но вызвали ваш метод «Display» с помощью указателя на базовый класс, будет вызван метод base, тогда как для «vDisplay» будет вызываться производный метод.

Например, попробуйте добавить следующие строки:

Base *b = &ba; 
b->Display(); 
b->vDisplay(); 
b = &de; 
b->Display(); 
b->vDisplay(); 

... и наблюдать вывод, как и ожидалось:

Основание: Non-виртуальный дисплей.
База: виртуальный дисплей.
База: не виртуальный дисплей.
Производные: Виртуальный дисплей.

+0

Привет @ sje397, спасибо за ваш ответ. Можете ли вы написать пример вызова метода, как вы сказали, указателем на базовый класс? Спасибо! –

+0

@Leif Lazar: сделано. – sje397

+0

также, как я уже сказал, вы также можете вызвать базовый метод (не виртуальный) из производного экземпляра, используя синтаксис разрешения разрешения. –

3

Да вы не поняли немного:

Чистые виртуальные функции:

virtual void fun1()=0 -> должен быть переопределен в производном классе

Виртуальные функции:

virtual void fun2() -> можно переопределить

Нормальные функции:

void fun3() -> не отменяет его

Для того, чтобы достичь выполнения полиморфизма вам необходимо переопределить виртуальные функции в C++

0

Я думаю, что это может быть также лучше смотреть на это в контексте статического и динамического связывания.

Если метод не является виртуальным (он уже по умолчанию используется в C++, в отличие от Java), то метод связывается с его вызывающим пользователем во время компиляции, что невозможно узнать о фактическом объекте, который будет указываться во время выполнения. Таким образом, тип переменной - это все, что имеет значение, которое является «базой».