虚拟功能的反直觉行为

时间:2011-12-16 11:02:05

标签: c++

鉴于

#include <string>
#include <iostream>


struct A  {
    virtual operator std::string() const { return "A"; }
    virtual operator const char *() const { return this->operator std::string().c_str(); }
};

struct B1 : public A {
    virtual operator std::string() const { return "<"; }
};

struct B2 {
    B2() { }
    virtual ~B2() { }
    virtual operator std::string() const { return ">"; }
    virtual operator const char *() const { return this->operator std::string().c_str(); }
};

struct C1 : public A {
    C1() { }
    virtual ~C1() { }
    virtual operator std::string() const { return "["; }
};

struct C2 {
    C2() { }
    virtual ~C2() { }
    virtual operator std::string() const { return "]"; }
    virtual operator const char *() const { return this->operator std::string().c_str(); }
};

int main() {
    using namespace std;
    cout << B1() << endl;
    cout << C1();
    cout << C2() << B2() << endl;
}

输出应为“&lt; []&gt;”。但是,它是“&lt; []]”。

  1. 我错了吗?如果是这样,为什么?
  2. 如果没有,那么这种行为的潜在原因是什么?

2 个答案:

答案 0 :(得分:5)

实际上,由于以下原因,您的代码行为未定义:

return this->operator std::string().c_str();

您正在临时调用c_str(),并稍后使用该结果。

您所看到的是未定义行为的有效表现。

现在,如果您对实际发生的事情感到好奇,可以将main()的最后一行修改为:

    cout << (const void*)C2() << ' ' << (const void*)B2() << endl;

如果你这样做,你可能会看到相同的地址被打印两次(在两种情况下都是悬空指针)。这就是我的电脑上发生的事情,我怀疑你的电脑会发生什么。 当然,由于行为未定义,这只是许多人的一种可能表现。

答案 1 :(得分:3)

你的问题真的归结为:

#include <string>
#include <iostream>

struct B2 {
    B2() { }
    virtual ~B2() { }
    virtual operator std::string() const { return ">"; }
    virtual operator const char *() const { return this->operator std::string().c_str(); }
};

struct C2 {
    C2() { }
    virtual ~C2() { }
    virtual operator std::string() const { return "]"; }
    virtual operator const char *() const { return this->operator std::string().c_str(); }
};

int main() {
    using namespace std;
    cout << C2() << B2() << endl;
}

很明显,这与虚拟功能无关。这里发生的是调用operator const char*,调用operator std::string,返回一个临时std::string,您可以从中返回.c_str()。由于在调用operator const char*之后此临时std::string被销毁,因此您有const char*指向已释放的内存。

现在任何事都可能发生,因为这是UB ......