我正在研究遗留框架。假设“A”是基类,“B”是派生类。这两个类都进行了一些关键的框架初始化。 FWIW,它使用 ACE图书馆很重。
我的情况是;创建了“B”的实例。但是“A”的构造函数依赖于一些只能从“B”执行的初始化。
正如我们所知,当“B”被实例化时,“A”的构造函数在“B”的构造函数之前被调用。 virtual
机制在 ctors 中不起作用,使用 static functions
被排除在外(由于 static-initialization-order-fiasco )。
我考虑过如下使用 CRTP 模式:-
template<class Derived>
class A {
public:
A(){
static_cast<Derived*>(this)->fun();
}
};
class B : public A<B> {
public:
B() : a(0) {
a = 10;
}
void fun() { std::cout << "Init Function, Variable a = " << a << std::endl; }
private:
int a;
};
但是在初始化器列表中初始化的类成员具有未定义的值,因为它们尚未执行(例如上述情况中的“a”)。在我的例子中,有许多这样的基于框架的初始化变量。
是否有任何众所周知的模式来处理这种情况?
提前致谢
更新:
根据 dribeas 的想法,我想出了一个临时解决方案来解决这个问题(完全重构目前不符合我的时间表)。以下代码将演示相同的内容:-
// move all A's dependent data in 'B' to a new class 'C'.
class C {
public:
C() : a(10)
{ }
int getA() { return a; }
private:
int a;
};
// enhance class A's ctor with a pointer to the newly split class
class A {
public:
A(C* cptr)
{
std::cout << "O.K. B's Init Data From C:- " << cptr->getA() <<
std::endl;
}
};
// now modify the actual derived class 'B' as follows
class B : public C, public A {
public:
B()
: A(static_cast<C*>(this))
{ }
};
有关相同内容的更多讨论,请参阅 this c.l.c++.m 上的链接。 Konstantin Oznobikhin 提供了一个很好的通用解决方案。
最佳答案
也许您能做的最好的事情就是重构。让基类依赖于其派生类型之一是没有意义的。
我以前见过这样的做法,给开发人员带来了相当大的痛苦:扩展 ACE_Task 类以提供可以使用具体功能扩展的周期性线程,并从周期性线程构造函数中激活线程只是为了发现在测试,而且通常情况下它是有效的,但在某些情况下,线程实际上在最派生的对象被初始化之前就开始了。
继承是一种强关系,只应在需要时使用。如果你看一下 boost 线程库(只是文档,不需要进入细节),或者 POCO 库你会看到他们将问题分为两部分:线程类控制线程执行并调用传递的方法在构造中对他们来说:线程控制与将要运行的实际代码分开,并且要运行的代码作为构造函数的参数接收这一事实保证它是在调用线程构造函数之前构造的。
也许您可以在自己的代码中使用相同的方法。将功能一分为二,无论派生类现在做什么,都应该移到层次结构之外(boost 使用仿函数,POCO 使用接口(interface),使用任何看起来最适合你的东西)。如果没有更好地描述您正在尝试做的事情,我真的无法详细介绍。
您可以尝试的另一件事(这是脆弱的,我不建议这样做)是将 B 类分解为独立于 A 的 C 类和继承自两者的 B 类,首先是 C,然后是 A(使用 HUGE那里有警告评论)。这将保证 C 将在 A 之前构造。然后使 C 子对象成为 A 的参数(通过接口(interface)或作为模板参数)。这可能是最快的黑客攻击,但不是一个好的黑客攻击。一旦你愿意修改代码,就把它做好。
关于c++ - 派生类构造函数依赖问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2047563/