12

我的问题不是关于从基类构造函数调用虚成员函数,而是指向虚成员函数的指针在基类构造函数中是否有效。

鉴于以下

class A
{
    void (A::*m_pMember)();

public:
    A() :
        m_pMember(&A::vmember)
    {
    }

    virtual void vmember()
    {
        printf("In A::vmember()\n");
    }

    void test()
    {
        (this->*m_pMember)();
    }
};

class B : public A
{
public:
    virtual void vmember()
    {
        printf("In B::vmember()\n");
    }
};

int main()
{
    B b;
    b.test();

    return 0;
}

这会为所有兼容的 c++ 编译器生成“In B::vmember()”吗?

4

6 回答 6

3

当应用于指针时,“有效”是一个特定术语。数据指针在指向对象或NULL;时有效 函数指针在指向函数 orNULL时有效,指向成员的指针在指向成员 or 时有效NULL

但是,根据您关于实际输出的问题,我可以推断您想问其他问题。让我们看看你的vmember函数 - 或者我应该说函数?显然有两个功能体。您可以只将派生的一个设为虚拟,因此这也证实了确实有两个vmember函数,它们都恰好是虚拟的。

现在,问题变成了在获取成员函数的地址时是否已经选择了实际函数。您的实现表明它们没有,并且这只发生在实际取消引用指针时。

必须以这种方式工作的原因是微不足道的。获取成员函数的地址不涉及实际对象,这是解析虚拟调用所需要的。让我演示给你看:

namespace {
  void (A::*test)() = &A::vmember;
  A a;
  B b;
  (a.*test)();
  (b.*test)();
}

当我们初始化test时,没有类型的对象A或根本没有对象B,但有可能获取 的地址&A::vmember。然后可以将相同的成员指针用于两个不同的对象。除了 "In A::vmember()\n" 和 "In B::vmember()\n" 之外还能产生什么?

于 2010-06-22T14:00:47.713 回答
3

指针是有效的,但是你必须记住,当通过指针调用虚函数时,它总是根据左侧使用的对象的动态类型来解析。这意味着当您从构造函数调用虚函数时,无论是直接调用它还是通过指针调用它都没有关系。在这两种情况下,调用都将解析为其构造函数当前正在工作的类型。这就是虚函数的工作方式,当您在对象构造(或销毁)期间调用它们时。

Note also that pointers to member functions are generally not attached to specific functions at the point of initalization. If the target function is non-virtual, they one can say that the pointer points to a specific function. However, if the target function is virtual, there's no way to say where the pointer is pointing to. For example, the language specification explicitly states that when you compare (for equality) two pointers that happen to point to virtual functions, the result is unspecified.

于 2010-06-22T18:05:35.690 回答
1

阅读这篇文章,深入讨论成员函数指针以及如何使用它们。这应该回答你所有的问题。

于 2010-06-22T12:00:12.010 回答
1

我找到了关于旧新事物的一些解释(Raymond Chen 的博客,有时被称为 Microsoft 的 Chuck Norris)。

当然,它没有说明合规性,但它解释了原因:

B b;

b.A::vmember(); // [1]

(b.*&A::vmember)(); // [2]

1 和 2 实际上调用了一个不同的函数......这真的很令人惊讶。这也意味着您实际上不能使用指向成员函数的指针来阻止运行时调度:/

于 2010-06-22T17:46:39.293 回答
0

我想不是。指向虚拟成员函数的指针是通过 VMT 解析的,因此与调用此函数的方式相同。这意味着它无效,因为在构造函数完成后填充了 VMT。

于 2010-06-22T11:59:55.380 回答
-1

IMO 是implementation defined获取虚函数的地址。这是因为虚函数是使用特定于编译器实现的vtables实现的。由于在类 ctor 的执行完成之前不能保证 vtable 是完整的,因此指向此类表(虚拟函数)中的条目的指针可能是implementation defined behavior.

几个月前我在这里问了一个有点相关的问题;这基本上说在 C++ 标准中没有指定虚函数的地址。

因此,无论如何,即使它对您有用,该解决方案也不会是可移植的。

于 2010-06-22T12:35:50.577 回答