在调用基类之前需要在成员上调用方法
Posted
技术标签:
【中文标题】在调用基类之前需要在成员上调用方法【英文标题】:Need to call method on member before calling base class 【发布时间】:2019-09-19 00:26:25 【问题描述】:我有类似下面的代码:
template<class BASE_TYPE = COdbcQuery>
class CRemoteQuery : public BASE_TYPE
CRemoteDatabase m_Db;
public:
CRemoteQuery()
: BASE_TYPE(&m_Db)
~CRemoteQuery()
;
我的问题是必须在将m_Db
传递给基本构造函数之前调用m_Db.Open()
。
如果我调用一个方法作为调用Open()
的基本构造函数的参数,它会失败,因为m_Db
尚未初始化。
我尝试在基类中创建一个虚方法,它会在初始化期间被调用并且这个类可以覆盖,但是模板类不能覆盖虚拟方法。
重组我的基类以使m_Db
不需要首先打开会引发很多难题。有没有办法做到这一点?
【问题讨论】:
虽然我同意@Sam Varshavchik,但我认为它突出了另一个问题。鉴于职责分离,CRemoteQuery
类应该处理数据库的打开,还是应该使用 依赖注入 为您提供已经打开的数据库?我会选择后者,但您可以像这样轻松地使用逗号运算符:BASE_TYPE((static_cast<void>(m_Db.Open()), &m_Db))
@jfh:我什至不确定如何使用 DI 来解决这个问题。此类通过在我只需要查询时管理自己的数据库来节省大量输入。无论如何,我试图在我的问题中解释我尝试了你的建议。但是如果因为m_Db
还没有被构造而失败。
@Johnathan Wood 好吧,您可以尝试在相同的逗号运算符表达式ala 位置new
中显式构造m_Db
,但这也是一个很大的代码气味。 IMO 这可能表明您应该重构和引入工厂等,因为您获得生命周期不确定的资源的想法闻起来......很臭。
【参考方案1】:
只需稍作改动即可轻松实现这一系列事件:
class CRemoteDB
protected:
CRemoteDatabase m_Db;
CRemoteDB()
m_Db.open();
;
template<class BASE_TYPE = COdbcQuery>
class CRemoteQuery : private CRemoteDB, public BASE_TYPE
public:
CRemoteQuery()
: BASE_TYPE(&m_Db)
~CRemoteQuery()
;
父类总是按声明顺序构造的。首先构造CRemoteDB
父类,然后在父类的构造函数中调用CRemoteDatabase::open()
。
然后BASE_TYPE
被构造,并获得指向打开的m_Db
的指针。
CRemoteQuery
可以从其父类访问m_Db
,与它是它自己的类成员时没有什么不同。
但是模板类不能覆盖虚方法。
附:谁告诉你那是错的。模板类当然可以覆盖虚拟方法。我在这里有大量的模板层次结构,所有覆盖其父类的虚拟方法,左右。
【讨论】:
另一种可能的解决方案可能是创建一个方法,执行此类初始化,并使用它的结果传递给基类,例如:auto& initAndReturn m_Db.open (); return m_db; CRemoteQuery () : BASE_TYPE (&initAndReturn ())
谢谢,虽然一个奇怪的修复这似乎是最好的答案。至于虚拟方法,我尝试从基类覆盖一个虚拟方法,但它从未被调用。当我用谷歌搜索时,我发现了像this这样的页面。
@AlgirdasPreidžius:正如我的问题中所述,我尝试过,但它失败了,因为 m_Db
尚未构建。
@JonathanWood 嗯.. 由于您所描述的原因,我考虑过此类代码是否是未定义的行为。但是,我想,我记得看到过类似的代码,而且它似乎工作正常。也许我的大脑在欺骗我,我记错了。我可能需要去然后睡觉:/
@AlgirdasPreidžius 取决于您如何使用该成员,这可能并不重要——例如,缓存对我稍后将使用的东西的引用。数据库的初始化逻辑,太丑了。以上是关于在调用基类之前需要在成员上调用方法的主要内容,如果未能解决你的问题,请参考以下文章