为什么执行错误的功能?

RTB*_*ard 4 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"); }
 };
Run Code Online (Sandbox Code Playgroud)

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

Both* createInstanceOfBoth () {
   return new Both();
}
Run Code Online (Sandbox Code Playgroud)

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

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;
};
Run Code Online (Sandbox Code Playgroud)

这就是问题所在.当我调用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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Enrolling.
Enrolling.
Run Code Online (Sandbox Code Playgroud)

我注意到,如果我改变的顺序Enroll,并Verify在声明Both类(class Both : public Verify, public Enroll {...}),相反的效果会发生:

Verifying.
Verifying.
Run Code Online (Sandbox Code Playgroud)

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

Enroll* createInstanceOfEnroll () {
   return new Both();
}
Verify* createInstanceOfVerify () {
   return new Both();
}
Run Code Online (Sandbox Code Playgroud)

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

Registry () {
    enrollGenerator = &createInstanceOfEnroll;
    verifyGenerator = &createInstanceOfVerify;        
}
Run Code Online (Sandbox Code Playgroud)

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

Enrolling.
Verifying.
Run Code Online (Sandbox Code Playgroud)

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

为了节省将这些放在一个可编辑的示例中的时间和麻烦,我已将此代码发布到https://gist.github.com/833304进行下载.

Jer*_*ock 7

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

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

  • 我仍然不明白如何调用正确的函数 (2认同)