У меня есть устаревший код, который вместо виртуальных функций использует поле kind
для динамической отправки. Это выглядит примерно так:
// Base struct shared by all subtypes
// Plain-old data; can't use virtual functions
struct POD
{
int kind;
int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();
};
enum Kind { Kind_Derived1, Kind_Derived2, Kind_Derived3 /* , ... */ };
struct Derived1: POD
{
Derived1(): kind(Kind_Derived1) {}
int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();
// ... plus other type-specific data and function members ...
};
struct Derived2: POD
{
Derived2(): kind(Kind_Derived2) {}
int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();
// ... plus other type-specific data and function members ...
};
struct Derived3: POD
{
Derived3(): kind(Kind_Derived3) {}
int GetFoo();
int GetBar();
int GetBaz();
int GetXyzzy();
// ... plus other type-specific data and function members ...
};
// ... and so on for other derived classes ...
и затем функции-члены класса POD
реализуются следующим образом:
int POD::GetFoo()
{
// Call kind-specific function
switch (kind)
{
case Kind_Derived1:
{
Derived1 *pDerived1 = static_cast<Derived1*>(this);
return pDerived1->GetFoo();
}
case Kind_Derived2:
{
Derived2 *pDerived2 = static_cast<Derived2*>(this);
return pDerived2->GetFoo();
}
case Kind_Derived3:
{
Derived3 *pDerived3 = static_cast<Derived3*>(this);
return pDerived3->GetFoo();
}
// ... and so on for other derived classes ...
default:
throw UnknownKindException(kind, "GetFoo");
}
}
POD::GetBar()
, POD::GetBaz()
, POD::GetXyzzy()
и другие члены реализованы аналогично.
Этот пример упрощен. Фактический код содержит около десятка различных подтипов POD
и пару десятков методов. Новые подтипы POD
и новые методы добавляются довольно часто, и поэтому каждый раз, когда мы делаем это, мы должны обновлять все эти switch
операторы.
Типичный способ справиться с этим - объявить члены-функции virtual
в классе POD
, но мы не можем этого сделать, потому что объекты находятся в общей памяти. Существует много кода, который зависит от того, являются ли эти структуры обычными старыми данными, поэтому даже если бы я мог найти какой-то способ иметь виртуальные функции в объектах с общей памятью, я бы не хотел этого делать.
Итак, я ищу предложения о том, как лучше всего это исправить, чтобы все знания о том, как вызывать методы подтипа, были централизованы в одном месте, а не разбросаны среди пары десятков switch
операторов в пара десятков функций.
Что мне приходит в голову, так это то, что я могу создать какой-то класс адаптера, который обернет POD
и использует шаблоны для минимизации избыточности. Но прежде чем идти по этому пути, я хотел бы знать, как другие справились с этим.