Mam starszego kodu, który zamiast funkcji wirtualnych używa pola kind
do dynamicznego wysyłania. Wygląda to mniej więcej tak:Wysyłanie dynamiczne w języku C++ bez funkcji wirtualnych
// 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 ...
a następnie członkowie funkcyjne klasy za POD
są realizowane tak:
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()
i inni członkowie są realizowane w podobny sposób.
Ten przykład jest uproszczony. Rzeczywisty kod ma około tuzina różnych podtypów POD
i kilkudziesięciu metod. Nowe podtypy POD
i nowe metody dodawane są dość często, więc za każdym razem, gdy to robimy, musimy zaktualizować wszystkie te instrukcje.
Typowym sposobem na obsłużenie tego byłoby zadeklarowanie elementów funkcji virtual
w klasie , ale nie możemy tego zrobić, ponieważ obiekty znajdują się we wspólnej pamięci. Jest dużo kodu, który zależy od tego, czy te struktury są zwykłymi danymi, więc nawet gdybym mógł znaleźć jakiś sposób na posiadanie wirtualnych funkcji w obiektach pamięci wspólnej, nie chciałbym tego robić.
Poszukuję więc sugestii, jak najlepiej to oczyścić, aby cała wiedza na temat metod wywoływania podtypów była scentralizowana w jednym miejscu, a nie rozproszona pośród kilkudziesięciu switch
kilkadziesiąt funkcji.
To, co mi się przydarza, to że mogę stworzyć jakąś klasę adaptera, która owija POD
i używa szablonów w celu zminimalizowania nadmiarowości. Zanim jednak rozpocznę tę drogę, chciałbym się dowiedzieć, jak inni sobie z tym poradzili.
Mówiłeś było dużo kodu w zależności od tej klasy. Czy możesz dodać do niego pola lub czy struktura musi pozostać taka sama? –
Struktura powinna pozostać zasadniczo taka sama. Posiadamy masę ogromnych tablic takich rzeczy we wspólnej pamięci i już przekraczamy granice wielkości pamięci. –
czy wszystkie procesy mają tę samą wersję biblioteki, czy nie? –