user2116990
user2116990

Reputation: 61

Typesafe casting of structs in c++

I have a two level hierarchy of structs. I want to send the top level parent ref as param into a function. Actual value of param will be bottomMost child. The function should cast the child to struct of type oneBelow the topParent. Function should succeed if child belongs to the casting parent, fail otherwise.

Below is the design:

struct Parent {
  ~Parent() = default;
}

struct Child1 : public Parent {
  ~Child1() = default;
}

struct Child2 : public Parent {
  ~Child2() = default;
}

struct Child11 : public Child1 {
  ~Child11() = default;
}

struct Child21 : public Child2 {
  ~Child21() = default;
}

someFunction (Parent* parent) {
  Child1 * child1 = dynamic_cast<Child1 *>(parent);
}

main() {
  Child11 child11;
  someFunction(child11);  // this should succeeed
  
  Child21 child21;
  someFunction(child21);  // this should throw

}

Job of someFunction() is to verify that the bottomMost child belongs to a particular parent. But someFunction() doesn't throw for child21. Can someone lmk how to achieve that?

Here is an example which works for two level casting. Dont know how to expand it to three levels: How do I cast a parent class as the child class

Any help is appreciated.

Upvotes: 0

Views: 284

Answers (1)

sweenish
sweenish

Reputation: 5202

From cppreference:

If the cast fails and new-type is a pointer type, it returns a null pointer of that type. If the cast fails and new-type is a reference type, it throws an exception that matches a handler of type std::bad_cast.

Your new_type is a pointer, therefore it will not throw. Your code, as provided, also does not compile (missing return types on functions, passing wrong arguments).

Here's your code, using a reference instead of a pointer to get the dynamic_cast to throw. And a version using pointers is provided as well that can also throw.

#include <exception>
#include <iostream>

struct Parent {
  virtual ~Parent() = default;
};

struct Child1 : public Parent {
  virtual ~Child1() = default;
};

struct Child2 : public Parent {
  virtual ~Child2() = default;
};

struct Child11 : public Child1 {
  ~Child11() = default;
};

struct Child21 : public Child2 {
  ~Child21() = default;
};

// void someFunction(Parent* parent) {
//   Child1* child1 = dynamic_cast<Child1*>(parent);
//   if (!child1) {
//     throw std::bad_cast();
//   }
// }

void someFunction(Parent& parent) {
  Child1& child1 = dynamic_cast<Child1&>(parent);
}

int main() {
  Child11 child11;
  someFunction(child11);  // this should succeeed

  Child21 child21;
  try {
    someFunction(child21);  // this should throw
  } catch (std::bad_cast) {
    std::cout << "Exception caught.\n";
  }
}

I assume this exercise is purely academic.

Upvotes: 1

Related Questions