我有一个具有虚函数的基类。我想在构造过程中调用该类,因为我希望为每个派生类调用该函数。我知道我无法在构造过程中调用虚拟函数,但我想不出一个优雅的(即避免重复代码)解决方案。
在构造过程中调用虚函数有哪些解决方法?
我想避免这种情况的原因是因为我不想创建只调用基类的构造函数。
class A {
public:
A() {
read();
}
// This never needs to be called
virtual void read() = 0;
}
class B:A {
public:
B():A() { };
read() { /*Do something special for B here.*/ }
}
class C:A {
public:
C():A() { };
read() { /*Do something special for C here.*/ }
}
PS:Python 的做法很简单raise NotImplementedError
in A::read()
。我正在回归 C++,但我比我想象的还要生疏。
常见问题解答的角度。
这是一个常见问题。
请参阅标题为“C++ 常见问题解答”的项目“好吧,但是有没有一种方法可以模拟这种行为,就好像动态绑定在我的基类构造函数中的 this 对象上起作用一样?”.
在提问之前检查常见问题解答(通常是谷歌搜索或 altavista)通常是个好主意。
问题为“派生类特定基初始化”。
需要明确的是,虽然上面的字面问题是
“在构造过程中调用虚拟函数有哪些解决方法?”
很明显,意思是
“基类怎么能B
被设计成每个派生类都可以指定期间发生的事情的一部分B
建造?”
一个主要的例子是 C 风格的 GUI 功能由 C++ 类包装。然后是将军Widget
构造函数可能需要实例化一个 API 级小部件,根据最派生的类,该小部件应该是按钮小部件或列表框小部件或其他什么。因此,最派生的类必须以某种方式影响发生的事情Widget
的构造函数。
换句话说,我们正在谈论派生类特定的基础构造.
Marshall Cline 称之为“构造期间动态绑定”,这在 C++ 中是有问题的,因为在 C++ 中,类中对象的动态类型T
建设和破坏,是T
。这有助于类型安全,因为在子对象已初始化或其初始化开始之前,不会在派生类子对象上调用虚拟成员函数。但主要成本是 DBDI(显然)无法以既简单又安全的方式完成。
可以在其中执行派生类特定的 init。
在问题中,派生类的特定操作被称为read
。这里我称之为derived_action
。有 3 个主要的可能性derived_action
被调用:
由实例化代码调用,称为分两期建设.
这本质上意味着手头有一个几乎不可用的未完全初始化的对象的可能性,一个僵尸对象。然而,随着 C++11 移动语义变得更加常见和接受(无论如何,可以通过使用工厂在一定程度上缓解它)。主要问题是,在构造的第二阶段,由于构造期间的动态类型更改,不存在针对未初始化子对象的虚拟调用的普通 C++ 保护。
调用者Derived
构造函数。
例如,derived_action
可以作为参数表达式调用Base
构造函数。一种并非完全不常见的技术是使用类模板来生成大多数派生类,例如供应电话derived_action
.
调用者Base
构造函数。
这意味着知识derived_action
必须动态或静态地传递给构造函数。一个好的方法是使用默认的构造函数参数。这导致了并行类层次结构的概念,即派生类操作的层次结构。
这个列表是按照复杂性和类型安全性逐渐提高的顺序排列的,而且据我所知,还反映了各种技术的历史使用情况。
例如。 1990 年初,在 Microsoft 的 MFC 和 Borland 的 ObjectWindows GUI 中,两阶段构建的库很常见,而截至 2014 年,这种设计现在被认为是非常糟糕的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)