Как вызвать переопределенную виртуальную функцию из функции базового класса? - PullRequest
0 голосов
/ 06 ноября 2011

Я только что понял, что слишком сильно упростил код и что он не отражает мою настоящую проблему. Я прошу прощения за то, что не был более конкретным. На самом деле я пытаюсь сделать следующее:

Демо онлайн :

#include<iostream>

class A
{
    public:
        A();

        virtual void f()= 0;
        void g();
};

A::A()
{
    g();
}

void A::g()
{
    f();
}

class B : public A
{
    public:
        B() {};
        void f() {};
};

int main()
{
    B b;
    return 0;
}

Я полагаю, что программа вызывает чисто виртуальную функцию A::f, поскольку B еще не было создано при вызове конструктора.

Это правильно и как я могу преодолеть эту проблему?

Пожалуйста, прости меня за то, что я дал слишком упрощенную задачу ранее.

Ответы [ 6 ]

5 голосов
/ 06 ноября 2011

Рабочий образец вашего кода, после того как я удалил много других ошибок.

#include<iostream>

class A 
{
    virtual void f()=0;
    public:
    void g();
};

void A::g() 
{
   f();
}

class B : public A 
{

    void f(){std::cout<<"Inside B::f";}
};

int main() 
{
    B b;
    b.g();
    return 0;
}

Выход:

Внутри B :: f

Отправьте свой настоящий код, чтобы получить реальные ответы.


EDIT:
Теперь, когда вы показали нам свой настоящий код (в нем были ошибки компиляции, я исправил их для вас). Я понимаю вашу проблему.

Когда вы создаете объект класса B с использованием B b;, это приводит к вызову конструктора базового класса A::A(), который, в свою очередь, вызывает метод g(). Обратите внимание, что g() является только методом Базового класса, поэтому это приводит к вызову A::g(). Это далее называет f(). Теперь вы ожидаете, что это должно вызвать B::f(), но это не так.

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

Применяя указанное выше правило, поскольку f() вызывается в конструкторе A,
this->f() звонит A::f(), а не B::f(). Более того, поскольку A::f() не имеет определения (поскольку вы его не предоставили), это приводит к исключению времени выполнения:

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

Компилятор не смог обнаружить это как ошибку времени компиляции, поскольку при virtual вызываемая функция определяется во время выполнения в зависимости от того, на что указывает this, а не статически. Компилятор не мог это обнаружить.

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

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

0 голосов
/ 06 ноября 2011

добавьте это в источник:

void B::f()
{
    printf("im B::f\n");
}

и ваша программа должна работать.

вы не можете создавать экземпляры A, потому что существует чисто виртуальный метод.

0 голосов
/ 06 ноября 2011
#include <iostream>

class A {
public:
    virtual void f() = 0;
    void g();
};

void A::g() {
    std::cout << "A::g" << std::endl;
    this->f();
}

class B : public A {
public:
    virtual void f();
};

void B::f()
{
    std::cout << "B::f" << std::endl;
}

int main() {
    B b;
    b.g();
    return 0;
}
0 голосов
/ 06 ноября 2011

Концептуально это должно работать. Я давно не был в C ++, но это не должно сильно отличаться от этого сценария в C #:

public class MyBase
{
    public virtual void PrintName() { }
    public void DoWork()
    {
        PrintName();
    }
}

public class MyDerivative : MyBase
{
    public override void PrintName()
    {
        Console.WriteLine("MyDerivative");
    }
}
0 голосов
/ 06 ноября 2011

После удаления ошибок компилятора, ваш код работает нормально .

0 голосов
/ 06 ноября 2011

Если сигнатура функции B :: f соответствует A :: f, то использование f () в A :: g должно вызывать B :: f так, как вы этого хотите. В приведенном выше примере они совпадают, и A :: g должен вызвать B :: f.

Если ваши реальные сигнатуры функций более сложны, чем приведенный выше пример, убедитесь, что их сигнатуры точно совпадают, или компилятор сочтет B :: f новой функцией вместо переопределения A :: f.

*: строго говоря, тип возвращаемого значения может немного отличаться, но я ожидаю, что это не имеет значения

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