代码之家  ›  专栏  ›  技术社区  ›  anorm

指向虚拟成员函数的指针在基类的构造函数中是否有效?

  •  12
  • anorm  · 技术社区  · 14 年前

    我的问题不是关于 打电话 来自基类构造函数的虚拟成员函数,但是 指针 到虚拟成员函数在基类构造函数中有效。

    给出以下内容

    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++编译器产生“在B::VMeNes()中吗?

    6 回复  |  直到 14 年前
        1
  •  3
  •   AnT stands with Russia    14 年前

    指针是有效的,但是您必须记住,当通过指针调用虚拟函数时,总是按照 动态 左侧使用的对象的类型。这意味着,当您从构造函数调用一个虚拟函数时,不管您是直接调用它还是通过指针调用它。在这两种情况下,调用都将解析为其构造函数当前正在工作的类型。这就是虚拟函数的工作原理,当您在对象构造(或销毁)期间调用它们时。

    还请注意,指向成员函数的指针通常不会在初始化时附加到特定函数。如果目标函数不是虚拟的,可以说指针指向一个特定的函数。但是,如果目标函数是虚拟的,就无法确定指针指向何处。例如,语言规范明确指出,当您比较(为了相等)指向虚拟函数的两个指针时,结果是 未指定的 .

        2
  •  3
  •   MSalters    14 年前

    “valid”是应用于指针时的特定术语。当数据指针指向对象或 NULL ;函数指针指向函数或 无效的 ,并且指向成员的指针在指向成员或 无效的 .

    然而,从你关于实际输出的问题中,我可以推断出你想问别的问题。让我们看看你的 vmember 函数-还是应该说函数?显然有两个函数体。您可以只将派生的一个虚拟化,这样也可以确认实际上有两个 维纳斯 功能,两者都是虚拟的。

    现在的问题是,取成员函数的地址时是否已经选择了实际的函数。您的实现表明它们不存在,并且只有当指针实际上被取消引用时才会发生这种情况。

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

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

    当我们初始化 test ,没有类型的对象 A B 不过,是否可以记下 &A::vmember . That same member pointer can then be used with two different objects. 除了“在a::vmember()\n”和“在b::vmember()\n”之外,这还能产生什么?

        3
  •  1
  •   berkus    14 年前

    this article 对于成员函数指针及其使用方法的深入讨论。这应该能回答你所有的问题。

        4
  •  1
  •   Matthieu M.    14 年前

    我发现了一些关于 Old New Thing (Raymond Chen的博客,有时被称为微软的Chuck Norris)。

    当然,它并没有提到合规性,但它解释了为什么:

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

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

        5
  •  0
  •   Andrey    14 年前

    我想没有。指向虚拟成员函数的指针是通过vmt解析的,所以调用这个函数的方式是一样的。这意味着它是无效的,因为vmt是在构造函数完成后填充的。

        6
  •  -1
  •   Community Mofi    7 年前

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

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

    因此,在任何情况下,即使它适用于您,解决方案也不会是可移植的。