我试图使用静态多态来创建装饰器模式。
至于为什么我不使用动态多态,请参阅此QA。基本上,我不能dynamic_cast
每个装饰器,以便访问仅在装饰器中存在的某些特定功能(而不是在基类A中)。
使用静态多态性已经克服了这个问题,但是现在我无法将装饰器中的所有et()
方法注册回基类A(作为回调或其他方式),因此调用A::et()
时,只有A::et()
和Z::et()
被执行。我希望所有A,X,Y,Z ::et()
都被执行(X,Y,Z的顺序无关紧要)。
如何使用以下结构执行此操作?
我可以在维基百科中看到CRTP应该允许您使用static_cast
访问派生类的成员,但是如果有多个派生模板类,您如何处理该问题?
如果静态多态无法实现这一点,但是动态多态可能会回复另一个问题吗?
struct I {
virtual void et() = 0;
};
class A : public I {
public:
A() {
cout << "A::ctor " ;
decList.clear();
}
void regDecorator(I * decorator)
{
if (decorator) {
cout << "reg= " << decorator << " ";
decList.push_back(decorator);
}
else
cout << "dec is null!" <<endl;
}
virtual void et()
{
cout << "A::et ";
cout << "declist size= " << decList.size() << endl;
list<I*>::iterator it;
for( it=decList.begin(); it != decList.end(); it++ )
static_cast<I *>(*it)->et();
}
std::list<I*> decList; //FIXME
};
template<typename Base>
class X: public Base {
public:
X(){
cout << "X::ctor ";
Base::regDecorator(this);
}
virtual void et(){
cout << "X::et" <<endl;
}
};
template<typename Base>
class Y: public Base {//public D {
public:
Y(){
cout << "Y::ctor ";
Base::regDecorator(this);
}
void et(){
cout << "Y::et" <<endl;
}
};
template<typename Base>
class Z: public Base {//public D {
public:
Z() {
cout << "Z::ctor ";
Base::regDecorator(this);
}
void et(){
cout << "Z::et" <<endl;
}
};
int main(void) {
Z<Y<X<A> > > mlka;
cout << endl;
mlka.et();
return 0;
}
该结构将用作从一组传感器获取数据的参考。 A类是基类,包含所有传感器的通用功能。这包括:
- data container (f.e. `boost::circular_buffer`) to hold an amount of timestamped sample data acquired from the sensor.
- a Timer used to measure some timed quantities related to the sensors.
- other common data and calculation methods (fe. `calculateMean()`, `calculateStdDeviation()`)
事实上,A::timer
将在完成时调用A::et()
,以便对采样数据执行某些统计计算。
类似地,X,Y,Z是传感器对象的类型,每个传感器对象负责从采样数据中提取不同类型的信息。并且X,Y,Z::et()
对数据执行不同类型的统计计算。目标是在A::Timer
等待时间过后立即执行此计算。这就是为什么我想从A :: et()访问所有X,Y,Z :: et()的原因。是否可以在不影响示例中显示的静态多态的情况下使用?
谢谢
答案 0 :(得分:2)
你开始使用mixins,所以最后使用它们 它遵循一个最小的工作示例:
#include<iostream>
struct I {
virtual void et() = 0;
};
template<typename... T>
struct S: I, private T... {
S(): T{}... {}
void et() override {
int arr[] = { (T::et(), 0)..., 0 };
(void)arr;
std::cout << "S" << std::endl;
}
};
struct A {
void et() {
std::cout << "A" << std::endl;
}
};
struct B {
void et() {
std::cout << "B" << std::endl;
}
};
int main() {
I *ptr = new S<A,B>{};
ptr->et();
delete ptr;
}
与原始代码一样,有一个接口I
,它提供了要调用的虚拟方法
S
实现了该接口并删除了作为参数包传递的一堆类型
无论何时在et
的特化上调用S
,它都会对用于特化它的每种类型调用相同的方法。
我想这个例子很清楚,可以作为最终代码的良好基础 如果我已经正确理解了真正的问题,这可能是适合您班级的设计。
修改强>
我正在尝试回复此答案的一些评论,要求提供更多详细信息。
S
的特化是构建它的所有(子)对象。
在上面的示例中,S<A, B>
<{1}}和A
。
这意味着B
可以扩展一个或多个类以提供公共数据,并且可以在以下示例中用于推送这些数据和其他子对象:
S