2017-01-18 5 views
4

по какой причине эта программа:C++ - сопзЬ ключевое слово в методах и перегрузки

#include <iostream> 
using namespace std; 
class Base { 
public: 
    Base() { cout << "Costruttore Base" << endl; } 
    virtual void foo(int) { cout << "Base::foo(int)" << endl; } 
    virtual void bar(int) { cout << "Base::bar(int)" << endl; } 
    virtual void bar(double) { cout << "Base::bar(double)" << endl; } 
    virtual ~Base() { cout << "Distruttore Base" << endl; } 
}; 
class Derived : public Base { 
public: 
    Derived() { cout << "Costruttore Derived" << endl; } 
    void foo(int) { cout << "Derived::foo(int)" << endl; } 
    void bar(int) const { cout << "Derived::bar(int)" << endl; } 
    void bar(double) const { cout << "Derived::bar(double) const" << endl; } 
    ~Derived() { cout << "Distruttore Derived" << endl; } 
}; 
int main() { 
    Derived derived; 
    Base base; 
    Base& base_ref = base; 
    Base* base_ptr = &derived; 
    Derived* derived_ptr = &derived; 
    cout << "=== 1 ===" << endl; 
    base_ptr->foo(12.0); 
    base_ref.foo(7); 
    base_ptr->bar(1.0); 
    derived_ptr->bar(1.0); 
    derived.bar(2); 
    return 0; 
} 

В вызове base_ptr->bar(1.0); называется Base::bar(double), а в derived_ptr->bar(1.0); называется Derived::bar(double) const.

Я понял, что это ключевое слово const, но я не понимаю, почему компилятор выбирает разные перегруженные функции.

Если удалить const ключевое слово, все работает, как ожидалось, вызвав в обоих случаях Derived::bar

+5

Используйте ключевое слово 'override', и компилятор скажет вам, что вы не переопределили базовую функцию – WhiZTiM

ответ

2

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

Так что либо удалите const в производном классе, либо добавьте const в подпись bar() в верхнем классе. (Или держать его, как это, но знаю, что теперь у вас есть две функции с именем бар() в производном классе, один из которых скрыт)

+0

Почему вызов на строку' output_ptr-> (1.0); 'вызывает Derived :: bar (double) const ? – kopiro

+0

@kopiro Почему нет? – Danh

+0

Потому что output_bar не 'const'. – kopiro

3

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

2

C++ 11 добавлена ​​override specifier для предотвращения такого рода сюрпризы. Используйте ключевое слово override, и компилятор только скомпилирует ваш код, если он переопределит.

Принимая якобы переопределить из bar(int) (это также относится и к bar(double):.

class Base { 
public: 
    .... 
    virtual void bar(int) { cout << "Base::bar(int)" << endl; } 
}; 

class Derived : public Base { 
public: 
    ... 
    //This isn't an override, program is well formed 
    void bar(int) const { cout << "Derived::bar(int)" << endl; } 
}; 

Функция bar член в Derived не переопределить базовый класс владеть Поскольку const квалификации различны, следовательно, сигнатуры функции-члена различны. Все, что вы сделали в производном классе, заключалось в том, чтобы добавить новую перегрузку и скрыть ее базовый класс.

Добавьте ключевое слово override в производный класс ', и компилятор даст диагностику, если она не переопределит.

class Base { 
public: 
    .... 
    virtual void bar(int) { cout << "Base::bar(int)" << endl; } 
}; 

class Derived : public Base { 
public: 
    ... 
    //This isn't an override, program is ill-formed, diagnostic required 
    void bar(int) const override { cout << "Derived::bar(int)" << endl; } 
}; 

Чтобы переопределить, подписи элементов-членов должны быть одинаковыми.

class Base { 
public: 
    .... 
    virtual void bar(int) { cout << "Base::bar(int)" << endl; } 
}; 

class Derived : public Base { 
public: 
    ... 
    //This overrides 
    void bar(int) override { cout << "Derived::bar(int)" << endl; } 
}; 

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

+0

Я не понимаю, почему вызов метода производной_пт-> bar (1.0); вызывает Derived :: bar (double) const? Base :: bar следует называть в любом случае, или нет? – kopiro

+0

@kopiro: как сказано в другом месте: методы 'bar', определенные в' Base', скрыты из-за скрытия имени, поэтому они не являются кандидатами на разрешение перегрузки. –

+0

@kopiro Вот как это происходит. Производный указатель указывает на экземпляр класса Derived. Итак, когда есть вызов любого метода, компилятор ищет класс Derived для метода с тем же именем. Нашел? ДА! бар (двойной) const. Таким образом, это функция, которая называется. – RoaaGharra

Смежные вопросы