【问题标题】:Virtual member functions and std::tr1::function: How does this work?虚成员函数和 std::tr1::function:这是如何工作的?
【发布时间】:2010-09-09 17:13:29
【问题描述】:

这是一段示例代码。请注意,BA 的子类,两者都提供了一个独特的print 例程。还要注意main 中的两个bind 调用都指向&A::print,尽管在后一种情况下传递了对B 的引用。

#include <iostream>
#include <tr1/functional>

struct A
{
    virtual void print()
    {
        std::cerr << "A" << std::endl;
    }
};

struct B : public A
{
    virtual void print()
    {
        std::cerr << "B" << std::endl;
    }
};

int main (int argc, char * const argv[])
{
    typedef std::tr1::function<void ()> proc_t;

    A a;
    B b;

    proc_t a_print = std::tr1::bind(&A::print, std::tr1::ref(a));
    proc_t b_print = std::tr1::bind(&A::print, std::tr1::ref(b));

    a_print();
    b_print();

    return 0;
}

这是我看到的使用 GCC 4.2 编译的输出:

A
B

我会考虑这种正确的行为,但鉴于std::tr1::functions 在这两种情况下都绑定到&amp;A::print,我无法解释它是如何正常工作的。有人可以请教我吗?

编辑:感谢您的回答。我熟悉继承和多态类型。我感兴趣的是&amp;A::print 是什么意思?它是否是 vtable 的偏移量,并且 vtable 会根据引用的对象(在本例中为 ab?)而变化,从更具体的角度来看,这段代码的行为如何正确?

【问题讨论】:

  • 如果使用TR1,则应标记为C++0x
  • @John:这段代码是在 gcc 4.2 下编译的 C++,不涉及 C++0x。能否请您澄清一下您的立场?
  • @fbrereto:tr1 命名空间中的所有内容均来自 C++0x 标准草案中的标准库提案;特别是技术报告 1 中的那些。en.wikipedia.org/wiki/C%2B%2B_Technical_Report_1
  • @fbereto:如果您使用 TR1 工具,则根据定义,您使用 C++0x。 TR1 C++0x
  • @John:不,TR1 不是 C++0x。 TR1 是 2005 年提出的一组库。C++0x 是标准的新修订版(希望)在 2011 年发布。TR1 库不是 C++ 标准库的一部分,这就是为什么它们都是在 std::tr1 命名空间中,而不是 std 命名空间。 TR1 库已包含在 C++0x 标准库中(为此,它们已移至 std 命名空间)。

标签: c++ inheritance tr1


【解决方案1】:

这与使用普通成员函数指针的方式相同。以下产生相同的输出:

int main ()
{
    A a;
    B b;
    typedef void (A::*fp)();
    fp p = &A::print;
    (a.*p)(); // prints A
    (b.*p)(); // prints B
}

如果 boost/tr1/std::function 做了任何不同的事情,那将是令人惊讶的,因为它们可能将这些指向成员函数的指针存储在引擎盖下。哦,当然,如果没有指向 the Fast Delegates article 的链接,就不能完整地提及这些指针。

【讨论】:

  • 当我看到这个问题时,我首先想到的是那篇文章!非常有趣和彻底。
【解决方案2】:

因为print() 被声明为virtual,所以A 是一个多态类。通过绑定到print 函数指针,您将通过A 指针调用,与以下方式非常相似:

A* ab = &b;
ab->print();

在上面的-&gt;print 调用中,您会期待多态行为。在您的代码中也是如此。如果你问我,这是一件好事。至少,大多数时候。 :)

【讨论】:

  • 您不仅绑定到 print(),它的行为如这里所述的多态,还绑定到从中调用它的对象。由于第二个绑定,对象的类型开始发挥作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
  • 2023-03-31
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
相关资源
最近更新 更多