-2

我刚刚意识到我将代码简化得太多了,它并没有反映我真正的问题。我很抱歉没有更具体。我实际上尝试做的是以下内容:

在线演示

#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在调用构造函数时尚未创建。

这是正确的,我该如何克服这个问题?

请原谅我之前给出了过于简单的问题。

4

6 回答 6

5

在我删除了许多其他错误之后,您的代码的工作示例

#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

发布您的真实代码,以获得真实的答案。


编辑:
现在,您向我们展示了您的真实代码(它有编译错误,我为您修复了它们)。我理解你的问题。

B当您使用 using创建一个类的对象时B b;,它会调用基类构造函数A::A(),而后者又会调用该方法g()。请注意,这g()只是一个基类方法,因此这会导致调用A::g(). 这进一步呼吁f()。现在你的期望是这应该调用B::f(),但它没有。

为什么?
请注意规则,
在构造函数或析构函数内部,对象this指向的类型始终是其构造函数/析构函数被调用的类型。

应用上述规则,Sincef()在 的构造函数中被调用A
this->f()调用A::f()而不是B::f()。此外,因为A::f()没有定义(因为您没有提供定义)它导致运行时异常:

称为终止的纯虚方法在没有活动异常的情况下被调用。

编译器无法将其检测为编译时错误,因为virtual要调用的函数是在运行时根据this指向而不是静态确定的。编译器无法检测到这一点。

我该如何克服这个问题?
您不能通过构造函数中的动态调度来做到这一点。
如果您从除构造函数/析构函数之外的任何其他方法调用它,您可以实现并期待您期望的行为。

避免在构造函数和析构函数中调用虚函数,因为它们不会调用您认为它们可能调用的版本。

于 2011-11-06T13:02:22.263 回答
0

删除编译器错误后,您的代码可以正常工作

于 2011-11-06T13:02:08.680 回答
0

从概念上讲,这应该有效。我已经很久没有接触过 C++ 了,但这与 C# 中的这种情况应该没有太大的不同:

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

public class MyDerivative : MyBase
{
    public override void PrintName()
    {
        Console.WriteLine("MyDerivative");
    }
}
于 2011-11-06T13:02:38.100 回答
0
#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;
}
于 2011-11-06T13:03:18.840 回答
0

如果 B::f 的函数签名与 A::f 匹配,那么在 A::g 中使用 f() 应该按照您的意愿调用 B::f。在您上面的示例中,它们确实匹配,并且 A::g 应该调用 B::f。

如果您的真实函数签名比上面给出的示例更复杂,请确保它们的签名完全匹配,否则编译器会将 B::f 视为新函数而不是 A::f 的覆盖。

*:严格来说,返回类型可能会略有不同,但我认为这与这里无关

于 2011-11-06T12:59:00.350 回答
0

在源代码中添加:

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

你的程序应该可以工作。

您不能创建 A 的实例,因为有一个纯虚方法。

于 2011-11-06T13:11:45.527 回答