В чем разница между одноименной унаследованной функцией и переопределенной виртуальной функцией? - PullRequest
2 голосов
/ 21 сентября 2010
#include <iostream> 
using namespace std;  

class base  
{  
public:  
    void f() {cout << "base" << endl;}  
    virtual void v() {cout << "base (virtual)" << endl;}  


};  

class deriv : public base  
{  
public:  
    void f() {cout << "deriv" << endl;}  
    void v() {cout << "deriv (overridden)" << endl;}  
};  


int main()  
{  
    base b;  
    b.f();  
    b.v();  

    deriv d;  
    d.f();  
    d.v();  
}

Я не понимаю, в чем реальная разница между этими двумя методами f и v: если я заменяю функцию другой с тем же именем, я не "заменяю" ее? Даже если я все еще могу получить к нему доступ, создав указатель base * и затем указав на него производный объект, я не понимаю, какое здесь «чистое» использование C ++.

Когда не используются виртуальные (то есть переопределяемые методы) методы, может кто-нибудь сказать мне, есть ли законное использование для этого, и чем отличается использование переопределенного виртуального метода?

РЕДАКТИРОВАТЬ: Я извиняюсь за использование плохого синтаксиса с уценкой, но уценка действительно плохой выбор, она сложная и довольно капризная (я предпочитаю текстильный хе-хе). РЕДАКТИРОВАТЬ 2: Извините, я не догадался, что кнопка 101010101010101 предназначена для вставки кода, я обычно просто делаю это вручную: (

Ответы [ 2 ]

6 голосов
/ 21 сентября 2010

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

Основная идея заключается в том, чтобы вы могли делать такие вещи:

class Animal
{
    public:
    virtual void talk() = 0;
};

class Dog : public Animal
{
    public:
    void talk() { cout << "Bark" << endl; }
};

class Cat : public Animal
{
    public:
    void talk() { cout << "Meow" << endl; }
};

void foo(Animal* a)
{
    a->talk();
}

Теперь, когдавы передаете указатель Animal в foo() и вызываете функцию-член talk(), она будет делать что-то другое в зависимости от того, указывает ли она на объект Cat или Dog.Дело в том, что foo() может работать с чем угодно, что наследуется от Animal.Кроме того, если через некоторое время вы создадите новый тип класса Animal, вы можете передать его в foo() без проблем и без необходимости изменения какого-либо кода внутри foo().

4 голосов
/ 22 сентября 2010

Вы увидите разницу между ними только при использовании указателя или ссылки.

deriv * d = new deriv;
d->f(); // "deriv"
d->v(); // "deriv (overridden)"

Как и ожидалось. Теперь мы приведем этот указатель к базовому указателю:

base * b = static_cast<base *>(d);
b->f(); // "base"
b->v(); // "deriv (overridden)"

Вызов виртуальной функции переходит к производной функции, даже если указатель является указателем на базовый класс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...