C++ 调用虚拟方法时崩溃

C++ 调用虚拟方法时崩溃,c++,C++,我在其他问题中了解到了这一点,但没有一个是类似的,一些是要在构造函数中调用虚拟方法,另一些是关于纯虚拟的,但这里的问题是关于不纯的vituais方法,而是关于不需要在所有派生类中实现的虚拟方法。如果实例化的类没有实现该方法,如果我们调用,它会从基逻辑上调用该方法,有时会崩溃。 我在想,为什么?它进入的地方是什么?解决这个问题的最好办法是什么 这是一个简单的例子,避免回答像纯虚拟的 #include <iostream> class Foo { public: virtual

我在其他问题中了解到了这一点,但没有一个是类似的,一些是要在构造函数中调用虚拟方法,另一些是关于纯虚拟的,但这里的问题是关于不纯的vituais方法,而是关于不需要在所有派生类中实现的虚拟方法。如果实例化的类没有实现该方法,如果我们调用,它会从基逻辑上调用该方法,有时会崩溃。 我在想,为什么?它进入的地方是什么?解决这个问题的最好办法是什么

这是一个简单的例子,避免回答像纯虚拟的

#include <iostream>

class Foo
{
public:
    virtual std::string myString() {}
};

class Bar : public Foo
{
public:
};

int main(int argc, char ** argv)
{
    Foo * bar = new Foo;
    bar->myString();

    return 0;
}
最好的解决方案是什么

抛出异常 使用assertfalse 返回默认值 避免实现实体,否则将导致 编译时间 别无选择 最好的答案是基于VTABLE解释为什么会发生这种情况,当然,选择一种解决方案并解释原因。这个想法不是基于观点。

基类确实实现了这个函数,只是实现错误而已。它与vtables或任何复杂的东西无关。首选解决方案4,因为它可以防止生成错误的程序(如果不可能/不希望按该顺序生成1或2)

请注意,该错误与虚拟函数或继承无关。通常,您不使用Bar,注意到了吗?。它甚至与类没有任何关系,但也会发生在任何独立函数中。考虑:

#include <iostream>
#include <string>

// Note: UB -- nothing returned
int getInt() {}
std::string getStr() {}

int main(int argc, char ** argv)
{
    // This probably works (read access from an arbitrary 
    // location on the stack which is in the prog's address space)
    std::cout << getInt() << std::endl;

    // This will crash. operator<< will try to access memory through
    // a pointer value which is some arbitrary byte pattern on the stack.
    // Probably not in the prog's address space.
    // Then the destructor for the temporary string will 
    // try to delete the same 
    // memory which will crash in any case, even if it happens to
    // point to valid memory (which, alas, was never allocated).
    std::cout << getStr();

    std::cout << "Still alive?\n"; // never printed
    std::cout.flush();

    return 0;
}
为了防止原始代码发生错误,只需返回一个值。如果您实现该函数,并且不抛出或中止这三个选项,即如果返回,则必须返回一个值:

#include <iostream>

class Foo
{
public:
    virtual std::string myString() { return "test\n";}
};

class Bar : public Foo
{
public:
};

int main(int argc, char ** argv)
{
    Foo * bar = new Foo();
    std::cout << bar->myString();

    return 0;
}

mystring函数应该返回字符串。

VTABLE是指向虚拟方法的指针表。通常,指向VTABLE的指针在视图中是隐藏的,但它通常作为类实例中的第一个元素实现


当派生类没有其父类实现为虚拟的成员函数时,将调用父类的方法。

此示例不会崩溃,是吗?展示一个能做到的。编辑:哦,天哪,是的。我很困惑。哦,函数没有返回任何东西。和虚拟问题无关。我很难看出类栏和这些有什么关系。您的方法不返回值,如果不返回,您的编译器应该从系统中删除。就处理它的最佳方式而言,将警告视为一个错误,.@SH.0x90我怀疑这不会持续很久,但重要的是要注意,您本质上是在问如何最好地处理格式错误的程序。对此只有一个可行的答案:不要编写格式错误的程序。你如何做到这一点,实际上是一个与计划本身的目标保持一致的品味和适当性的问题。正如WhozCraig所提到的,如果你把警告视为错误,你从一开始就不会有问题。我在一个设置了选项的编译器中运行了你的程序,但它首先拒绝编译。因此,唯一的最佳解决方案是返回默认值。为什么选择返回默认值?还有其他解决方法。@SH.0x90 vtable是当今编译器多态性的经典实现。根据C++,这是实现依赖的。可能会有编译器发明另一种根本不使用vtable的技术。好吧,如果要实现它,必须返回一个值、抛出或中止。我只是想说明崩溃的发生是因为调用方没有预期的字符串。为什么选择返回默认值?还有其他方法可以解决这个问题。你希望它以什么方式工作?您可以返回一些其他值,这些值可以调用一些其他函数等。VTABLE是一个完全不同的东西。VTABLE lookup发生在您声明基类virtual的成员函数时,这意味着,如果派生类的指针是使用为基类分配的内存生成的,请在父类中查找。我不希望基类具有纯virtual,因为我想要它的一个实例,而其他类则是从这个类扩展而来,并没有实现基类的所有方法,但我们知道,偶尔有人会调用一个未实现的方法,它需要调用基类的方法。一个纯虚函数需要由一个非抽象的派生类来实现,当然,你们并没有这样做。如果您返回任何内容,它不会成为纯虚拟函数。其次,如果您担心派生类的使用是偶然的,那么可以将这些函数设置为基类的私有函数。第三,您仍然可以创建基类的实例。