vlad_tepesch
vlad_tepesch

Reputation: 6883

safe dynamic_cast from c-Structure?

I have some C-structures that are used through some algorithms that link together c++ parts.

On the input end there is a c++ structure that inherits from the c structure to add some members. at the output end there are some components that also may require this data.

Is there a safe way to detect if this C structure actually is the mentioned c++ class? maybe by making c++ child classes polymorphic and using dynamic casts?

struct Cstruct{
  int someData;
};


class CPPclass: public Cstruct{
  CPPclass(){};
  int someMoreData;
};

so maybe something like

class CPPclass: public Cstruct{
  virtual ~CPPclass(){};
  CPPclass(){};
  int someMoreData;
};

void test(Cstruct* i_c){
  auto cpp = dynamic_cast<CPPclass*>(i_c);   // < does not work, because Cstruct is not polymorphic
  if(cpp){
      // da;
  }
}

but maybe?:

class CPPclassHelper: public Cstruct{
  virtual ~CPPclassHelper(){};
  CPPclassHelper(){};
  int someMoreData;
};

class CPPclass: public CPPclassHelper{
  virtual ~CPPclassHelper(){};
};

void test(Cstruct* i_c){
  auto cpph = static_cast<CPPclassHelper*>(i_c); 
  auto cpp = dynamic_cast<CPPclass*>(cpph );   
  if(cpp){
      // da;
  }
}

Upvotes: 2

Views: 316

Answers (1)

eerorika
eerorika

Reputation: 238331

You could maintain the type information yourself. Use a static set of all pointers to Cstruct that are bases of CPPclass. Insert the base in all constructors of CPPclass and remove in the destructor. Safe cast can then be implemented using a lookup into that set.

Here is an example:

struct CPPclass: Cstruct{
    CPPclass(){
        bases.insert(this);
    };
    CPPclass(const CPPclass&){
        bases.insert(this);
    };
    CPPclass(CPPclass&&){
        bases.insert(this);
    };
    ~CPPclass(){
        bases.erase(this);
    };

    static CPPclass* safe_cast(Cstruct* c) {
        auto it = bases.find(c);
        return it == bases.end()
            ? nullptr
            : static_cast<CPPclass*>(*it);
    }

private:
    static std::unordered_set<Cstruct*> bases;
};

Usage:

int main() {
    CPPclass cpp;
    Cstruct  c;

    Cstruct* ptr_cpp = &cpp;
    Cstruct* ptr_c   = &c;

    std::cout << CPPclass::safe_cast(ptr_cpp) << '\n'; // some address equal to &cpp
    std::cout << CPPclass::safe_cast(ptr_c)   << '\n'; // null
}

Upvotes: 1

Related Questions