CRTP 또는 컴파일 타임 다형성은 컴파일 타임에 모든 유형을 알고있는 경우를위한 것입니다. addWidget
을 사용하여 런타임에 위젯 목록을 수집하고 fooAll
및 barAll
길이라면 동등한 위젯 목록의 구성원을 런타임에 처리해야하므로 런타임에 다른 유형을 처리 할 수 있어야합니다. 그래서 당신이 제시 한 문제에 대해서, 당신은 런타임 다형성 (polymorphism)을 사용하여 붙어 있다고 생각합니다.
표준 대답은 물론, 다음
당신이 정말로 런타임 다형성을 피하기 위해 필요한 경우 ... 당신이 그것을 피하려고하기 전에 런타임 다형성의 성능이 문제가 있음을 확인하려면 다음 중 하나입니다 해결책이 효과가있을 수 있습니다.
옵션 1 : 위젯
하여 WidgetCollection의 회원이 컴파일 타임에 알려진 경우, 당신은 아주 쉽게 템플릿을 사용할 수 있습니다의 컴파일시 모음을 사용합니다.
template<typename F>
void WidgetCollection(F functor)
{
functor(widgetA);
functor(widgetB);
functor(widgetC);
}
// Make Foo a functor that's specialized as needed, then...
void FooAll()
{
WidgetCollection(Foo);
}
옵션 2 : 자유의 기능 정말
class AbstractWidget {
public:
virtual AbstractWidget() {}
// (other virtual methods)
};
class WidgetCollection {
private:
vector<AbstractWidget*> defaultFooableWidgets;
vector<AbstractWidget*> customFooableWidgets1;
vector<AbstractWidget*> customFooableWidgets2;
public:
void addWidget(AbstractWidget* widget) {
// decide which FooableWidgets list to push widget onto
}
void fooAll() {
for (unsigned int i = 0; i < defaultFooableWidgets.size(); i++) {
defaultFoo(defaultFooableWidgets[i]);
}
for (unsigned int i = 0; i < customFooableWidgets1.size(); i++) {
customFoo1(customFooableWidgets1[i]);
}
for (unsigned int i = 0; i < customFooableWidgets2.size(); i++) {
customFoo2(customFooableWidgets2[i]);
}
}
};
미운, 그리고 OO와 런타임 다형성을 교체합니다. 템플리트는 모든 특별한 경우를 나열 할 필요성을 줄임으로써이를 지원할 수 있습니다. 다음과 같은 것을 시도해보십시오 (완전히 테스트되지 않음). 그러나이 경우에는 인라인되지 않습니다.
class AbstractWidget {
public:
virtual AbstractWidget() {}
};
class WidgetCollection {
private:
map<void(AbstractWidget*), vector<AbstractWidget*> > fooWidgets;
public:
template<typename T>
void addWidget(T* widget) {
fooWidgets[TemplateSpecializationFunctionGivingWhichFooToUse<widget>()].push_back(widget);
}
void fooAll() {
for (map<void(AbstractWidget*), vector<AbstractWidget*> >::const_iterator i = fooWidgets.begin(); i != fooWidgets.end(); i++) {
for (unsigned int j = 0; j < i->second.size(); j++) {
(*i->first)(i->second[j]);
}
}
}
};
옵션 3 : 그것은 복잡성을 관리 할 수 있기 때문에 그것은 변화의 얼굴에 안정성을 유지하는 데 도움이 있기 때문에 제거 OO
OO 유용합니다. 상황에 따라 수천 개의 위젯, 일반적으로 동작이 변경되지 않고 멤버 메소드가 매우 간단하다는 점을 설명하는 것처럼 보입니다. 관리하기 위해 복잡성이나 변경 사항이별로 없을 수도 있습니다. 그렇다면 OO가 필요하지 않을 수 있습니다.
"가상"메소드 및 알려진 하위 클래스 (OO가 아님)의 정적 목록을 유지해야하며 가상 함수 호출을 다음과 같은 점프 테이블로 대체 할 수 있다는 점을 제외하면이 솔루션은 런타임 다형성과 동일합니다. 인라인 함수.
class AbstractWidget {
public:
enum WidgetType { CONCRETE_1, CONCRETE_2 };
WidgetType type;
};
class WidgetCollection {
private:
vector<AbstractWidget*> mWidgets;
public:
void addWidget(AbstractWidget* widget) {
widgets.push_back(widget);
}
void fooAll() {
for (unsigned int i = 0; i < widgets.size(); i++) {
switch(widgets[i]->type) {
// insert handling (such as calls to inline free functions) here
}
}
}
};
C++의 마이너 생성자는 가상 일 수 없습니다. –
oops, 죄송합니다. –
기본 클래스 "AbstractWidget" "WidgetCollection"을 변경하거나 다른 개발자/커뮤니티가 디자인 할 수 있습니까? – umlcat