我的目的是建立一些基类CBaseClass
,其中包括CBaseMember
类型成员的容器;然后导出一个CDerivedClass : public CBaseClass
,其中包含CDerivedMember : public CBaseMember
。
我无法使用指向CBaseMember
的指针并使用CDerivedMember
中的CDerivedClass
对象对其进行初始化,因为它是一个多重继承的情况,CDerivedMember
有一个额外的接口(纯粹的抽象基类,与CBaseClass
实现无关,但需要CDerivedClass
可见。很多肮脏的铸造是我非常想避免的。
我解决这个问题的方法是让CBaseClass
成为一个模板,如下所示:
//declaration
template <class Member>
CBaseClass
{
protected:
virtual void GenericMethod();
virtual void VirtualMethod() = 0;
Member* member;
};
//definition
template <class Member>
void CBaseClass<Member>::GenericMethod()
{
member->SomeMemberMethod();
}
然后从中继承CDerivedClass
,如下所示:
//declaration
CDerivedClass : public CBaseClass<CDerivedMember>
{
protected:
virtual void VirtualMethod();
};
//definition
void CDerivedClass::VirtualMethod()
{
member->SomeDerivedMethod();
}
可以预见,这不起作用(CBaseClass<CDerivedMember>::GenericMethod()
由于不明原因而未解决),但遗憾的是我不知道如何更改我的代码以表示我想要它的含义。
任何人都可以解释一下这些事情是如何正确完成的 - 或者为我的问题提出另一种解决方案吗?
谢谢!
答案 0 :(得分:0)
好吧,你可以将脏的类型转换保存在一个地方,封装在你的班级中。因此,它不再那么脏了。
class CBaseMember {
public:
virtual void SomeMemberMethod(){}
};
class CDerivedMember : public CBaseMember {
public:
virtual void SomeMemberMethod() { /* do other stuff */ }
virtual void SomeDerivedMethod() {}
};
//declaration
class CBaseClass
{
protected:
virtual void GenericMethod();
virtual void VirtualMethod() = 0;
CBaseMember* member;
virtual CBaseMember * getMember() {
return member;
}
};
//definition
void CBaseClass::GenericMethod()
{
getMember()->SomeMemberMethod();
}
//declaration
class CDerivedClass : public CBaseClass
{
protected:
virtual void VirtualMethod();
virtual CDerivedMember * getMember() {return static_cast<CDerivedMember *>(member);}
};
//definition
void CDerivedClass::VirtualMethod()
{
getMember()->SomeDerivedMethod();
}
总之,您在派生类的getMember()
方法中执行脏类型转换。此时,您应确保该成员的类型无论如何都是CDerivedMember
。因此,只要您知道您拥有的指针属于CDerivedClass
类型,就可以访问其CDerivedMember
而无需进行类型转换。如果你必须回到CBaseClass
指针,那么在访问其成员时你自然会回到CBaseMember
。
答案 1 :(得分:0)
我怀疑您想摆脱模板,因为您提供的代码段可以使用(如果您在类型声明中添加了class
关键字)。
如果您想避免从CBaseMember*
向CDerivedMember*
投降,您可以通过动态绑定和协方差来处理这种情况:
class CBaseClass {
private:
CBaseMember* const baseMember;
protected:
virtual CBaseMember* member() const {
// ^^^^^^^^^^^
return baseMember;
}
/* everything else you need here. Just never ever access `baseMember` directly */
};
class CDerivedClass : public CBaseClass {
private:
CDerivedMember* const derivedMember;
protected:
virtual CDerivedMember* member() const {
// ^^^^^^^^^^^^^^
return derivedMember;
}
/* everything else you need here. Just never ever access `derivedMember` directly */
};
但是,这只有在您永远不会将成员更改为指向其他位置的情况下才有效,因为您无法使用setter来提取此技巧:virtual void CBaseClass::member(CBaseMember*)
无法使用virtual void CDerivedClass::member(CDerivedMember*)
覆盖。
请注意,您仍会在baseMember
周围携带CDerivedClass
指针,但它永远不会被使用。因此,如果记忆对你很重要,那么这可能是不可行的。