Jasmine
Jasmine

Reputation: 16185

c++ can one turn a string value into a type?

I am trying to write some generic code:

int _pID = _plant->getPlantInternalID();
std::string _plantName = getPlantBasedUponInternalID(_pID);

_plantName returns a string of the plant, like Broccoli

but is there a way to do something like this:

for (int f=0; f < _f.getPlants().size(); f++)
{        
    std::shared_ptr<Plant> sbas = _f.getPlants().at(f);

    std::shared_ptr<_plantName> sder2 = std::dynamic_pointer_cast<_plantName>(sbas);
}

notice I am putting in _plantName but really I need to do something like:

std::shared_ptr<Broccoli> sder2 = std::dynamic_pointer_cast<Broccoli>(sbas);    

what is needing to do something like this called and how do I accomplish it?

UPDATE: I am just getting the ID based upon an internal ID I made up:

std::string HUDForStatus::getPlantBasedUponInternalID(int _id)
{
    switch (_id)
    {
        case 114: // Asparagus
            return ASPARAGUS::plantName.c_str();
            break;
        case 113: // Beets
            return BEETS::plantName.c_str();
            break;
        case 115: // Bok Choy
            return BOKCHOY::plantName.c_str();
            break;
        case 107: // Broccoli
            return BROCCOLI::plantName.c_str();
            break;
        case 101: // Carrot
            return CARROT::plantName.c_str();
            break;
        case 110: // Celery
            return CELERY::plantName.c_str();
            break;
        case 103: // Corn
            return CORN::plantName.c_str();
            break;
        case 116: // Eggplant
            return EGGPLANT::plantName.c_str();
            break;
        case 102: // Green Beans
            return GREENBEANS::plantName.c_str();
            break;
        ... <snip>...
}

}

Upvotes: 0

Views: 199

Answers (3)

BЈовић
BЈовић

Reputation: 64223

c++ is statically typed language, and it is not possible to create variables of some random type at run-time. You could do it if your classes have a common interface, as shown in the example at the end.

To get a unique name of a type at run-time is easy with typeid.


#include <iostream>
#include <string>
#include <typeinfo>
#include <memory>

struct B
{
  virtual ~B(){}
  virtual void foo() = 0;
};
struct A1 : B
{
  virtual void foo()
  {
    std::cout << 1 << std::endl;
  }
};
struct A2 : B
{
  virtual void foo()
  {
    std::cout << 2 << std::endl;
  }
};

std::unique_ptr<B> getFooCaller( const std::string v )
{
  if ( v==typeid(A1()).name() )
  {
    return std::unique_ptr<B>(new A1);
  }
  else if ( v==typeid(A2()).name() )
  {
    return std::unique_ptr<B>(new A2);
  }

  return 0;
}

int main(int argc, char* argv[])
{
  if (argc!=2)
  {
    std::cout << "pass type name" << std::endl;
  }

  auto b = getFooCaller(argv[1]);
  if (b)
  {
    b->foo();
  }
  else
  {
    std::cout << "expecting  " << typeid(A2()).name() <<"  or  " << typeid(A2()).name() << std::endl;
  }
}

Upvotes: 0

4pie0
4pie0

Reputation: 29724

std::shared_ptr<T> std::dynamic_pointer_cast<std::shared_ptr<U>& sp >

can only work when

dynamic_cast<T*>(sp.get()) 

would work. So in your case

std::shared_ptr<_plantName> sder2 = std::dynamic_pointer_cast<_plantName>(sbas);

conversion Plant* to std::string should be valid through dynamic_cast. For this to happen, std::string should be derived from Plant, and this means also that these types should be polymorphic (for this some virtual function is needed), because the dynamic_cast operator uses the runtime type information generated from polymorphic classes. But it is not possible.

solution:

1. derive your classes from Plant - then conversion like

std::shared_ptr<Broccoli> sder2 = std::dynamic_pointer_cast<Broccoli>(sbas);

will be possible. this might be of help.

2 . use abstract interface which Plant will implement. Then you will use methods from this interface to do dynamic type identification at runtime

Upvotes: 0

Mark B
Mark B

Reputation: 96251

This is not the C++ way to solve the problem. Instead, give Plant an appropriate abstract interface and then you don't NEED to know which concrete type you're working with. Instead you just use the interface and let the virtual dispatch decide which plant it is and which implementation to call.

Upvotes: 3

Related Questions