在调用虚拟方法时崩溃

时间:2014-07-11 11:34:18

标签: c++

我在其他问题中读过它,但没有一个是类似的,有些是在构造函数中调用虚方法,有些是关于纯虚拟方法,但这里的问题是关于vituais方法不是纯粹的,而是虚拟的不需要在所有衍生类中实现的方法。如果实例化的类没有实现该方法,那么如果我们调用它,它会在逻辑上从基类调用该方法,并且它有时会崩溃。 我在想,为什么?什么是VTABLE(它进入的地方)?什么是解决它的最佳方法。

这是一个简单的例子,(避免回答像纯虚拟的那样)。

#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;
}

什么是最好的解决方案?

  1. 抛出异常
  2. 使用assert(false)
  3. 返回默认值
  4. 避免实施正文,否则会导致错误 编译时间
  5. 没有其他选择
  6. 最好的答案将是解释为什么会发生这种情况的基础上的VTABLE,当然,选择一个解决方案并解释原因。这个想法不是基于意见。

3 个答案:

答案 0 :(得分:2)

基类实现实现该函数,它只是错误地实现了它。它与vtable或任何复杂的东西无关。解决方案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;
}

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

您的mystring函数应该返回一个字符串。