我今天遇到了令人困惑的情况,我希望有人可以向我解释。
我有一个包含4个类的C ++程序:
Base
类,它只是一个公共接口,Enroll
类,其子类Base
并具有纯虚拟enroll()
方法,Verify
类,它也是Base
的子类,并且具有纯虚拟verify()
方法,Both
类,它同时是Enroll
和Verify
的子类,并提供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()
函数的函数指针来提供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;
};
这就是问题所在。当我在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
)的声明中更改Both
和class Both : public Verify, public Enroll {...}
的顺序,则会产生相反的效果:
Verifying.
Verifying.
我已经确定了一种解决方法,在其中使用两个不同命名的函数,而不是使用单个createInstanceOfBoth()
函数来创建我的Enroll
和Verify
对象,但是不同的回报类型:
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以供下载。
答案 0 :(得分:6)
该函数指针强制转换(将函数返回Both*
作为返回Verify*
或Enroll*
)是不正确的;在具有多重继承的情况下,对象内的不同基类不一定从对象的开头开始。函数指针强制转换不执行从Both*
转换为基本指针类型的派生到基础指针所需的偏移操作。
您可以拥有一个createInstanceOfBoth
功能,但需要返回Both*
;然后,调用它的代码将使用该结果执行派生到基础的转换。