Oleg Vazhnev
Oleg Vazhnev

Reputation: 24057

at runtime how to determine actual type of non-polymorphic type

I have such declarations:

struct InstrumentInfo
{
    std::string Name;
    TradingStatus Status;
    myDecimal MinStep;
    std::string ISIN;
    myDecimal limit_down;
    myDecimal limit_up;
};

struct FortsDerivativeInfo : InstrumentInfo
{
    std::string ShortIsin;
    int IsinId;
    std::string CodeVcb;
    myDecimal StepPrice;
    int LotVolume;
    myDecimal exch_pay;
};

struct StockInfo : InstrumentInfo
{
    int LotSize;
};

I've trited to write such code:

if (auto si = dynamic_cast<StockInfo*>(ii))
{
    LOT_SIZE = si->LotSize;
}
else
{
    LOT_SIZE = 1;
}

This doesn't compile, I receive "error C2683: 'dynamic_cast' : 'InstrumentInfo' is not a polymorphic type". How can I fix this error?

If I replace dynamic_cast to static_cast code compiles, but as static_cast doesn't perform any runtime checks I'm afraid this will not work?

Upvotes: 2

Views: 116

Answers (3)

Matthieu M.
Matthieu M.

Reputation: 299730

The short answer is: dynamic_cast only works on polymorphic types, so you have to look for alternatives.


The longer answer is that you have alternatives:

  • the simplest is to add a virtual method (the destructor of the base class), and your code will compile as is
  • but in general, if you can use virtual method, create one that will avoid this ugly cast
  • other alternatives exist, such as having an enum in the base class that indicate which child is currently instantiated; they are not as automated so are of last recourse

Upvotes: 0

T.C.
T.C.

Reputation: 137301

No run-time type information is available for non-polymorphic types (types without virtual functions).

Adding a virtual destructor in InstrumentInfo will give you RTTI and make dynamic_cast work, though the better way to solve your problem is, as pointed out in the other answer, to use a virtual member function that returns lot size. It's a good idea to use a virtual destructor regardless of RTTI anyway, because otherwise you have some serious problems if you do this:

InstrumentInfo * info = new FortsDerivativeInfo;
delete info;

This results in undefined behavior (deleting a derived object through a base class pointer without a virtual destructor).

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

Run-time type information is available only for types that have at least one virtual function (i.e. "polymorphic types"). The only way to make dynamic_cast work is to make the base type polymorphic - for example, by declaring its destructor virtual.

A better approach would be removing the need for the cast altogether - for example, by making a virtual lotSize function:

struct InstrumentInfo
{
    std::string Name;
    TradingStatus Status;
    myDecimal MinStep;
    std::string ISIN;
    myDecimal limit_down;
    myDecimal limit_up;
    virtual int lotSize() const { return 1; }
};

struct StockInfo : InstrumentInfo
{
    int LotSize;
    virtual int lotSize() const { return LotSize; }
};

InstrumentInfo ii;
LOT_SIZE = ii.lotSize();

Upvotes: 2

Related Questions