I am struggling to express a list containing various derived class instances in a container object according to a common interface. Adding them to a vector affords options, using the base class, pointers and references. Casting them to concrete types using a discriminator is proving problematic later.
In C#, give or take, I would express it this way:
public interface IOrderable
{
decimal GetUnitPrice( );
}
public class BaseProduct
{
public Guid Id {get;set;}
public string Name {get;set;}
public decimal UnitPrice {get;set;}
//
public GetUnitPrice( return UnitPrice; }
}
public class Digital : BaseProduct, IOrderable
{
public int Bytes {get;set;}
}
public class Physical : BaseProduct, IOrderable
{
public int MassInGrammes {get;set}
}
public class Order
{
public List<IOrderable> listOfItems;
public int TotalBytes()
{
int t = 0;
foreach( var i in listOfItems )
{
var d = i as Digital; // <-- in C# this patterny works fine
if( d != null ) t = t + d.Bytes;
}
return t;
}
public decimal TotalMass() { ... }
}
When I try to achieve this in C++, I begin with the base class, and create a vector.
class BaseProduct
{
public:
string type; // <-- discriminator
etc.
}
class Order
{
public:
vector<BaseProduct> listOfItems;
int totalBytes() {
int t=0;
for( BaseProduct bp: listOfItems )
{
if( bp.type == "digital" )
... and this is where the wheels come off
how to go from BaseProuct to Digital?
if( bp.type == "physical" )
... etc.
}
return t;
}
}
If I create a list based on pointers I can see how to reinterpret_cast to a known derived type. This is my best guess.
I could not get a version with references to objects to work - the vector definition - closest was wrapped_reference<object&>.
I feel am making heavy weather of this, largely because of C++'s focus on object ownership/lifetime, and the general advice that pointers are somehow evil, even in modern C++. (How things have changed! C++ WAS pointer-land once!)
What then is a good (not necessarily best) pattern for this kind of mixed type list in C++?
(Please note, the above is only pseudo code, the problem emerged in a knarly byte-level message parser, where there is one class per message type. Two is enough to find a pattern.)
Aucun commentaire:
Enregistrer un commentaire