为什么执行错误的功能?

时间:2011-02-18 05:50:58

标签: c++ function-pointers multiple-inheritance

我今天遇到了令人困惑的情况,我希望有人可以向我解释。

我有一个包含4个类的C ++程序:

  • 一个Base类,它只是一个公共接口,
  • Enroll类,其子类Base并具有纯虚拟enroll()方法,
  • 一个Verify类,它也是Base的子类,并且具有纯虚拟verify()方法,
  • Both类,它同时是EnrollVerify的子类,并提供enroll()verify()的实现

像这样:

 class Base {
    public:
       Base () { }
       virtual ~Base () { }
 };

 class Enroll : public virtual Base {
    public:
       virtual ~Enroll () { }
       virtual void enroll () = 0;
 };

 class Verify : public virtual Base {
    public:
       virtual ~Verify () { }
       virtual void verify () = 0;
 };

 class Both : public Enroll, public Verify {
    public:
       virtual ~Both () { }

       virtual void enroll () { printf ("Enrolling.\n"); }
       virtual void verify () { printf ("Verifying.\n"); }
 };

Both的实例在非成员函数中实例化,它只创建一个新的Both并返回指针:

Both* createInstanceOfBoth () {
   return new Both();
}

最后,有一个Registry类,基本上只是作为Enroll / Verify工厂。它使用一对createInstanceOfBoth()函数的函数指针来提供EnrollVerify的实例:

typedef Enroll* (*EnrollGenerator) ();
typedef Verify* (*VerifyGenerator) ();

class Registry {
   public:
      Registry () {
          enrollGenerator = (EnrollGenerator)&createInstanceOfBoth;
          verifyGenerator = (VerifyGenerator)&createInstanceOfBoth;              
      }

      Enroll* getEnroll () { return enrollGenerator (); }
      Verify* getVerify () { return verifyGenerator (); }

      EnrollGenerator enrollGenerator;
      VerifyGenerator verifyGenerator;
};

这就是问题所在。当我在getEnroll()对象上调用Registry并在返回的对象上调用enroll()时,我会看到正确的预期输出:Enrolling.。但是当我调用getVerify()并在返回的对象上调用verify()时,再次执行enroll()方法

代码:

int main () {
   Registry registry;
   Enroll *enroller;
   Verify *verifier;

   enroller = registry.getEnroll ();
   verifier = registry.getVerify ();
   enroller->enroll ();
   verifier->verify ();
   return 0;
}

输出:

Enrolling.
Enrolling.

我注意到如果我在Enroll类(Verify)的声明中更改Bothclass Both : public Verify, public Enroll {...}的顺序,则会产生相反的效果:

Verifying.
Verifying.

我已经确定了一种解决方法,在其中使用两个不同命名的函数,而不是使用单个createInstanceOfBoth()函数来创建我的EnrollVerify对象,但是不同的回报类型:

Enroll* createInstanceOfEnroll () {
   return new Both();
}
Verify* createInstanceOfVerify () {
   return new Both();
}

然后,在Registry类中,我创建了指向这些函数的函数指针:

Registry () {
    enrollGenerator = &createInstanceOfEnroll;
    verifyGenerator = &createInstanceOfVerify;        
}

当我现在运行程序时,我得到预期的输出:

Enrolling.
Verifying.

我的问题是:为什么第一种方法不起作用?我怀疑它与将createInstanceOfBoth()转换为具有不同返回类型的函数指针有关,但我并不完全清楚究竟发生了什么。我现在使用我的解决方法很好,但我很好奇:有没有办法只使用单个createInstanceOfBoth()函数来实现这一点,而不必使用两个相同的函数但具有不同的返回类型? / p>

为了节省将这些内容整合到一个可编辑示例中的时间和麻烦,我已将此代码发布到https://gist.github.com/833304以供下载。

1 个答案:

答案 0 :(得分:6)

该函数指针强制转换(将函数返回Both*作为返回Verify*Enroll*)是不正确的;在具有多重继承的情况下,对象内的不同基类不一定从对象的开头开始。函数指针强制转换不执行从Both*转换为基本指针类型的派生到基础指针所需的偏移操作。

您可以拥有一个createInstanceOfBoth功能,但需要返回Both*;然后,调用它的代码将使用该结果执行派生到基础的转换。