1

Encountered this issue while studying for a test, would appericiate a brief explenation.
If I have a class Object and another one : class Point : public Object
Now, If I get Object& O1 and Object& O2 , but Object can be Point too...
So my main question is how can I check if both of them are Point Because I need to access a field that Object doesnt have

Here are the two classes :

Class Object {
public :
some functions
};

Class Point : Public Object {
double x;
double y;
public:
same functions different implementation
};

I wanna access x,y but I need to make sure its a Point first.

Thanks in advance

Nadav Peled
  • 951
  • 1
  • 13
  • 19

4 Answers4

7

You can use dynamic_cast

Object &o = ...;
if(Point *p = dynamic_cast<Point*>(&o)) {
  // ...
}

If the dynamic type of o is a Point or derives from it, the code within the if will be executed with p being readily available (the static type of o is Object).

If you already know that it is a Point, you can use references

Point &p = dynamic_cast<Point&>(o);
// ...

For this to work, there must at least be one virtual function (if only the destructor) in Object.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    @NadavPeled not necessarily, if you happen to derive from `Point` again. But that then depends more precisely on what you want to do. Normally it suffices if the object "*is-a* `Point`", and you don't normally want a "*is-a* `Point` but *is-not-a* `SuperGoodPoint`" – Johannes Schaub - litb Jul 29 '13 at 20:44
  • I see, So you're saying that If I know that one part of the equation is a Point, typeid would work, but the more general and correct way to check this out is by using a dynamic cast ? – Nadav Peled Jul 29 '13 at 20:49
3

Generally, if you "need" to know this, you are doing it wrong. There are a few exceptions, but as a rule, you should not need to know which type of object you are "using". Your functions that are different should be declared as virtual, so that the code that is doing something with an Object can just call the relevant function in Point if the object is a Point type object.

If you want to access x and y, your should be doing that indirectly through a virtual function that performs whatever action needs to be done on x and y. If you really need to touch x and y when you only have (a reference or pointer to) an Object, you are simply at the wrong level.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Yes, Of Course, as Written above, I'm preparing for a test and it is a part of some "dry" questions about the material where we need to know the behavior of some code.. – Nadav Peled Jul 29 '13 at 20:46
1

You can rely on the type information provided by the C++ Standard Library. The following example has been extracted from cppreference.com:

#include <iostream>
#include <typeinfo>
#include <string>
#include <utility>

class person
{
  public:

   person(std::string&& n) : _name(n) {}
   virtual const std::string& name() const{ return _name; }

  private:

    std::string _name;
};

class employee : public person
{
   public:

     employee(std::string&& n, std::string&& p) :
         person(std::move(n)), _profession(std::move(p)) {}

     const std::string& profession() const { return _profession; }

   private:

     std::string _profession;
};

void somefunc(const person& p)
{
   if(typeid(employee) == typeid(p))
   {
      std::cout << p.name() << " is an employee ";
      auto& emp = dynamic_cast<const employee&>(p);
      std::cout << "who works in " << emp.profession() << '\n';
   }
}

int main()
{
   employee paul("Paul","Economics");
   somefunc(paul);
}
Escualo
  • 40,844
  • 23
  • 87
  • 135
  • Uhm, but you can have `class manager: public employee` - is a manager an `employee`? no, but the `manager` has all the properties of an `employee`, but also some extras (e.g. what/who (s)he's manager of), which won't be in an `employee`. – Mats Petersson Jul 29 '13 at 20:50
  • If manager is not an employee, then it should not inherit from employee (inheritance is meant to model the "is-a" relationship). – Escualo Aug 01 '13 at 18:16
  • Yes, my point was that a `manager` "is-a" `employee`, but the `typeid(employee)` is not equal to `manager`, so that method is not going to work reliably in that case. – Mats Petersson Aug 01 '13 at 18:19
0

It may be sloppy but if you have a pointer or reference to an object you can always invoke a dynamic_cast. if the pointer is returned as nullptr then you know your object is not a derived class of the desired object.

class CBase { 
      virtual void dummy(){}
};
class CDerived: public CBase {
    int a;
};

int main () {
  try {
    CBase * pba = new CDerived;
    CBase * pbb = new CBase;
    CDerived * pd;

    pd = dynamic_cast<CDerived*>(pba);
    if (pd==0) cout << "Null pointer on first type-cast" << endl;

    pd = dynamic_cast<CDerived*>(pbb);
    if (pd==0) cout << "Null pointer on second type-cast" << endl;

  } catch (exception& e) {cout << "Exception: " << e.what();}
  return 0;
}
HopAlongPolly
  • 1,347
  • 1
  • 20
  • 48
  • I think you mean "if the pointer is returned as **0**", because dynamic_cast returns 0 when it fails. – Tiago Costa Jul 29 '13 at 20:43
  • Can you please explain how dynamic cast will fail when trying to cast an Object to a Point ? – Nadav Peled Jul 29 '13 at 20:44
  • And also explain that this is probably a poor design - yes, there are situations when you REALLY need to do this - but so far in the 10 years since I started using C++ professionally, I have only seen code that does this in a small number of places (3-4 that I can think of). – Mats Petersson Jul 29 '13 at 20:47
  • @Nadav Peled Think of it like a square and a rectangle. A square is a rectangle but not all Rectangles are Squares. In this case a Point is an Object but not all Objects are Points. so a nullptr would be returned – HopAlongPolly Jul 29 '13 at 20:55