Ошибка компилятора виртуального метода C ++ / переопределение - PullRequest
0 голосов
/ 31 января 2012

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

//Base.h
class Base{
    public:
        void method(const objectType1& stuff1); 
        //objectType1 is whatever type you what (int, string, ...)

    protected:      
        Base(void);
        virtual ~Base(void);

        virtual void method(void) = 0;
};

//Derived.h
/*FINAL - DO NOT INHERIT THIS CLASS OR YOU WILL die :)*/
class Derived : public Base{
    public:
        Derived(void);
        ~Derived(void);

    private:
        void method(void);
};


//Main.cpp
int main(){
    objectType1 ot1;

    //this code works
    Base *bd = new Derived;
    bd->method(ot1);

    //this dosen't
    Derived *dd = new Derived;
    dd->method(ot1); 
    // he doesn't call Base::method(const objectType1& stuff1),
    // he calls Derived::method(void)

    return 0;
}

Я решил проблему, переименовав виртуальный методvoid method(void) в другом и все хорошо.

Мои вопросы:

  • Почему компилятор не знает, как вызвать метод из базового класса?
  • И почему я вижу void method(void) вmain поскольку он объявлен как protected в Base и private в Derived?(это какой-то побочный эффект)

Спасибо :).

Ответы [ 2 ]

3 голосов
/ 31 января 2012

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

Доступ к методу проверяется статически в статическом типе ссылки / указателя, через который отправляется вызов, даже если он будет динамически отправлен.

С другой стороны, во втором случае вызов осуществляется через производный тип, и спецификатор доступа проверяется на том уровне, где компилятор находит функцию-член равной private и таким образом жалуется.

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

1 голос
/ 31 января 2012

Определение метода в Derived скрывает определение в Base. Чтобы избежать этого, добавьте using Base::method; к Derived.

Это происходит потому, что при вызове функций в Derived компилятор просматривает Base только в том случае, если он не точил имя в Derived. Обратите внимание, что он не ищет подпись , а только имя на этом этапе. Разрешение перегрузки на основе подписи выполняется только после этого. На самом деле это не сильно отличается от следующей ситуации:

void function(int);
void function();

int main()
{
  void function(); // this declaration hides *both* global declarations
  function(3); // error
}

В вашем случае Base играет роль глобальной области видимости, а Derived - роль области действия функции.

Также обратите внимание, что это не связано с виртаульскими функциями; действительно, то же самое произошло бы и без virtual (за исключением того, что вы, конечно, не могли бы вызвать Derived method через указатель на Base, конечно, но вместо этого вызывали бы версию Base).

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